diff --git a/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/project.pbxproj b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000000000000000000000000000000..d5f0946a8c756347be67915f6643fd2243dd3eab --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/project.pbxproj @@ -0,0 +1,1798 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0289606657F3E1B14D87F2BC /* ofxSliderGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E661ACAA5BEC5B96FD2F6532 /* ofxSliderGroup.cpp */; }; + 06B42CCB73078EB0E8E265EE /* IpEndpointName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 552D90E7024A93518E711979 /* IpEndpointName.cpp */; }; + 0B9EEAF6D1EBB25B81373273 /* OscReceivedElements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 333B161A45E42EF09ADEC7A5 /* OscReceivedElements.cpp */; }; + 10C531C84875D2C829391B4E /* maxiGrains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 300B4DCCFFECBD546568227A /* maxiGrains.cpp */; }; + 1A04D8C41FC31D0E00D725DC /* RapidBitalino.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A04D8C31FC31D0E00D725DC /* RapidBitalino.cpp */; }; + 1A04D8D81FC38F3700D725DC /* libRAPID-MIX_API.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A04D8D71FC38F3700D725DC /* libRAPID-MIX_API.a */; }; + 1A7329231FC304D0001E730B /* machineLearning.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0030991FC3043900E02B93 /* machineLearning.cpp */; }; + 1A7329241FC304D0001E730B /* rapidGVF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A00309C1FC3043900E02B93 /* rapidGVF.cpp */; }; + 1A7329251FC304D0001E730B /* rapidXMM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A00309F1FC3043900E02B93 /* rapidXMM.cpp */; }; + 1A7329261FC304D0001E730B /* trainingData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0030A11FC3043900E02B93 /* trainingData.cpp */; }; + 1A73293D1FC304D5001E730B /* rapidPiPoHost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0030A61FC3043900E02B93 /* rapidPiPoHost.cpp */; }; + 1A732F4E1FC30565001E730B /* GVF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7329411FC30563001E730B /* GVF.cpp */; }; + 1A732FC91FC30566001E730B /* libpipo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A732B001FC30563001E730B /* libpipo.a */; }; + 1A732FCF1FC30566001E730B /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B301FC30563001E730B /* README.md */; }; + 1A732FD01FC30566001E730B /* BayesianFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B341FC30563001E730B /* BayesianFilter.cpp */; }; + 1A732FD11FC30566001E730B /* filter_utilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B361FC30563001E730B /* filter_utilities.cpp */; }; + 1A732FD21FC30566001E730B /* finitedifferences.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B391FC30563001E730B /* finitedifferences.c */; }; + 1A732FD31FC30566001E730B /* bbpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B3C1FC30563001E730B /* bbpr.cpp */; }; + 1A732FD41FC30566001E730B /* rpoly.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B3E1FC30563001E730B /* rpoly.cpp */; }; + 1A732FD51FC30566001E730B /* rta_bpf.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B431FC30563001E730B /* rta_bpf.c */; }; + 1A732FD61FC30566001E730B /* rta_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B471FC30563001E730B /* rta_int.c */; }; + 1A732FD71FC30566001E730B /* rta_util.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B4D1FC30563001E730B /* rta_util.c */; }; + 1A732FD81FC30566001E730B /* rta_bands.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B501FC30563001E730B /* rta_bands.c */; }; + 1A732FD91FC30566001E730B /* rta_biquad.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B521FC30563001E730B /* rta_biquad.c */; }; + 1A732FDA1FC30566001E730B /* rta_correlation.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B541FC30563001E730B /* rta_correlation.c */; }; + 1A732FDB1FC30566001E730B /* rta_cubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B561FC30563001E730B /* rta_cubic.c */; }; + 1A732FDC1FC30566001E730B /* rta_dct.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B581FC30563001E730B /* rta_dct.c */; }; + 1A732FDD1FC30566001E730B /* rta_delta.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B5A1FC30563001E730B /* rta_delta.c */; }; + 1A732FDE1FC30566001E730B /* rta_fft.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B5C1FC30563001E730B /* rta_fft.c */; }; + 1A732FDF1FC30566001E730B /* rta_lifter.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B5F1FC30563001E730B /* rta_lifter.c */; }; + 1A732FE01FC30566001E730B /* rta_lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B611FC30563001E730B /* rta_lpc.c */; }; + 1A732FE11FC30566001E730B /* rta_mean_variance.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B631FC30563001E730B /* rta_mean_variance.c */; }; + 1A732FE21FC30566001E730B /* rta_mel.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B651FC30563001E730B /* rta_mel.c */; }; + 1A732FE31FC30566001E730B /* rta_moments.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B671FC30563001E730B /* rta_moments.c */; }; + 1A732FE41FC30566001E730B /* rta_onepole.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B691FC30563001E730B /* rta_onepole.c */; }; + 1A732FE51FC30566001E730B /* rta_preemphasis.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B6B1FC30563001E730B /* rta_preemphasis.c */; }; + 1A732FE61FC30566001E730B /* rta_resample.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B6D1FC30563001E730B /* rta_resample.c */; }; + 1A732FE71FC30566001E730B /* rta_selection.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B6F1FC30563001E730B /* rta_selection.c */; }; + 1A732FE81FC30566001E730B /* rta_svd.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B711FC30563001E730B /* rta_svd.c */; }; + 1A732FE91FC30566001E730B /* rta_window.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B731FC30563001E730B /* rta_window.c */; }; + 1A732FEA1FC30566001E730B /* PiPoCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732B781FC30563001E730B /* PiPoCollection.cpp */; }; + 1A732FF41FC30566001E730B /* libsvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732BB51FC30563001E730B /* libsvm.cpp */; }; + 1A7330041FC30566001E730B /* classification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E881FC30565001E730B /* classification.cpp */; }; + 1A7330051FC30566001E730B /* dtw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E8A1FC30565001E730B /* dtw.cpp */; }; + 1A7330061FC30566001E730B /* fastDTW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E971FC30565001E730B /* fastDTW.cpp */; }; + 1A7330071FC30566001E730B /* knnClassification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E991FC30565001E730B /* knnClassification.cpp */; }; + 1A7330081FC30566001E730B /* modelSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E9B1FC30565001E730B /* modelSet.cpp */; }; + 1A7330091FC30566001E730B /* neuralNetwork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E9D1FC30565001E730B /* neuralNetwork.cpp */; }; + 1A73300A1FC30566001E730B /* rapidStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732E9F1FC30565001E730B /* rapidStream.cpp */; }; + 1A73300B1FC30566001E730B /* regression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732EA11FC30565001E730B /* regression.cpp */; }; + 1A73300C1FC30566001E730B /* searchWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732EA31FC30565001E730B /* searchWindow.cpp */; }; + 1A73300D1FC30566001E730B /* seriesClassification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732EA51FC30565001E730B /* seriesClassification.cpp */; }; + 1A73300E1FC30566001E730B /* svmClassification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732EA71FC30565001E730B /* svmClassification.cpp */; }; + 1A73300F1FC30566001E730B /* warpPath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732EAA1FC30565001E730B /* warpPath.cpp */; }; + 1A7330141FC30566001E730B /* jsoncpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732EC71FC30565001E730B /* jsoncpp.cpp */; }; + 1A73301B1FC30566001E730B /* readme.md in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F121FC30565001E730B /* readme.md */; }; + 1A73301C1FC30566001E730B /* xmmAttribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F161FC30565001E730B /* xmmAttribute.cpp */; }; + 1A73301D1FC30566001E730B /* xmmJson.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F1A1FC30565001E730B /* xmmJson.cpp */; }; + 1A73301E1FC30566001E730B /* xmmGaussianDistribution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F1E1FC30565001E730B /* xmmGaussianDistribution.cpp */; }; + 1A73301F1FC30566001E730B /* xmmModelSharedParameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F251FC30565001E730B /* xmmModelSharedParameters.cpp */; }; + 1A7330201FC30566001E730B /* xmmModelSingleClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F271FC30565001E730B /* xmmModelSingleClass.cpp */; }; + 1A7330211FC30566001E730B /* xmmPhrase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F2A1FC30565001E730B /* xmmPhrase.cpp */; }; + 1A7330221FC30566001E730B /* xmmTrainingSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F2C1FC30565001E730B /* xmmTrainingSet.cpp */; }; + 1A7330231FC30566001E730B /* xmmGmm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F301FC30565001E730B /* xmmGmm.cpp */; }; + 1A7330241FC30566001E730B /* xmmGmmParameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F321FC30565001E730B /* xmmGmmParameters.cpp */; }; + 1A7330251FC30566001E730B /* xmmGmmSingleClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F341FC30565001E730B /* xmmGmmSingleClass.cpp */; }; + 1A7330261FC30566001E730B /* xmmHierarchicalHmm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F371FC30565001E730B /* xmmHierarchicalHmm.cpp */; }; + 1A7330271FC30566001E730B /* xmmHmmParameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F391FC30565001E730B /* xmmHmmParameters.cpp */; }; + 1A7330281FC30566001E730B /* xmmHmmSingleClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F3C1FC30565001E730B /* xmmHmmSingleClass.cpp */; }; + 1A7330291FC30566001E730B /* xmmKMeans.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F3F1FC30565001E730B /* xmmKMeans.cpp */; }; + 1A73302A1FC30566001E730B /* xmmKMeansParameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A732F411FC30565001E730B /* xmmKMeansParameters.cpp */; }; + 1AF8F4F41FBFBA56007845B3 /* bitalino.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF8F4F21FBFBA56007845B3 /* bitalino.cpp */; }; + 1F4CACB1B7D09B43508A7EC3 /* ofxButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E76982C6091099847AF4A689 /* ofxButton.cpp */; }; + 230128348F328F3A83D41798 /* UdpSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 138DE2396984C9C63DA7FDD6 /* UdpSocket.cpp */; }; + 39B159E39B6636BFC65B0F2A /* NetworkingUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54C5AF569662A8351667313E /* NetworkingUtils.cpp */; }; + 460809B55AD9FA35FEEF18E9 /* maxiBark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E79D78A192005C0D7FDA98C0 /* maxiBark.cpp */; }; + 617ACA40B63357D76A9595A8 /* ofxOscReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F5FFC9C08A87AE48EA5E66C /* ofxOscReceiver.cpp */; }; + 638D65104AC275AFCB576B80 /* OscPrintReceivedElements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EFE170390703388444A995C /* OscPrintReceivedElements.cpp */; }; + 66078BCDF7C6B8F85391BD78 /* OscTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E87C4F253FACA6BBF714AD99 /* OscTypes.cpp */; }; + 6DEA5ACAF78C6AE7BB6BFDCF /* stb_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 8DC5D79A78655BF028FBDE30 /* stb_vorbis.c */; }; + 77C1DBAB01757716D71545F7 /* maximilian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC22E5BFC33148A93E906A /* maximilian.cpp */; }; + 7BF363788124DFB219FEA2D9 /* ofxOscBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1661CDE0EE45AC19EF11DA8E /* ofxOscBundle.cpp */; }; + 821FDA0B1E4F7BB6AF683071 /* maxiFFT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D7D4C890B7E7E86CF67EDE9 /* maxiFFT.cpp */; }; + 83944CBA55088BC6E0CB8655 /* ofxOscMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D39514497AFC9A4AAE903696 /* ofxOscMessage.cpp */; }; + 982961365190FE97577EC25D /* maxiMFCC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C590EAED7C04204257DE2745 /* maxiMFCC.cpp */; }; + 9B232A695C4183B7E9D6DE6B /* ofxGuiGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 161030033DD4104A32E68FA8 /* ofxGuiGroup.cpp */; }; + 9DB59557693F5AF1C3B86978 /* ofxLabel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C85AEC4A09E7407508E41723 /* ofxLabel.cpp */; }; + A22B63CBE8E52759908258DF /* OscOutboundPacketStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 16F2E6A76B43CC86E0875826 /* OscOutboundPacketStream.cpp */; }; + A6B3D68D6CAF91615E79B729 /* ofxPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3646FFD002EE9FED0DD367F3 /* ofxPanel.cpp */; }; + AE5D0283C3A439F21F24D146 /* maxiAtoms.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21080C6D8829F198543F568E /* maxiAtoms.cpp */; }; + BE5879D980EF1A321B38BDED /* ofxToggle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BA6903E0287C0B3CBF81989 /* ofxToggle.cpp */; }; + C061F0FB55B94C461FF5D520 /* ofxOscParameterSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB987CA7BF7FB3A39EF3514 /* ofxOscParameterSync.cpp */; }; + C0A43D1F56B1198FC5EE7031 /* ofxOscSender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEC6D21EB03AE1B72B35D0D9 /* ofxOscSender.cpp */; }; + C1CCEDB5321AA5A832D215F0 /* ofxSlider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 951C54CCCD72A0FFC773653F /* ofxSlider.cpp */; }; + CBF1E66610EC3ED02B8E7810 /* fft.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC8DE4E32DB58B5849214F05 /* fft.cpp */; }; + E4328149138ABC9F0047C5CB /* openFrameworksDebug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E4328148138ABC890047C5CB /* openFrameworksDebug.a */; }; + E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B69E1D0A3A1BDC003C02F2 /* main.cpp */; }; + E4B69E210A3A1BDC003C02F2 /* ofApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */; }; + E6E8C6BA7D5DD18D84DCE6B9 /* ofxBaseGui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 283D3449127FCD4AE5F47F88 /* ofxBaseGui.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + E4328147138ABC890047C5CB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = E4B27C1510CBEB8E00536013; + remoteInfo = openFrameworks; + }; + E4EEB9AB138B136A00A80321 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = E4B27C1410CBEB8E00536013; + remoteInfo = openFrameworks; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + E4C2427710CC5ABF004149E2 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 008629CF1C50CAC655956424 /* maximilian.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = maximilian.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maximilian.h; sourceTree = SOURCE_ROOT; }; + 0972B751F7A633CC3CCD4C70 /* TimerListener.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = TimerListener.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/TimerListener.h; sourceTree = SOURCE_ROOT; }; + 09AEC4E5ECE805EAD349DBCE /* PacketListener.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = PacketListener.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/PacketListener.h; sourceTree = SOURCE_ROOT; }; + 0D0D8D193987B4296465A319 /* ofxOscReceiver.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOscReceiver.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscReceiver.h; sourceTree = SOURCE_ROOT; }; + 0FEC22E5BFC33148A93E906A /* maximilian.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = maximilian.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maximilian.cpp; sourceTree = SOURCE_ROOT; }; + 138DE2396984C9C63DA7FDD6 /* UdpSocket.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = UdpSocket.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/posix/UdpSocket.cpp; sourceTree = SOURCE_ROOT; }; + 161030033DD4104A32E68FA8 /* ofxGuiGroup.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxGuiGroup.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxGuiGroup.cpp; sourceTree = SOURCE_ROOT; }; + 1661CDE0EE45AC19EF11DA8E /* ofxOscBundle.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxOscBundle.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscBundle.cpp; sourceTree = SOURCE_ROOT; }; + 16F2E6A76B43CC86E0875826 /* OscOutboundPacketStream.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = OscOutboundPacketStream.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.cpp; sourceTree = SOURCE_ROOT; }; + 1A0030971FC3043900E02B93 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; + 1A0030991FC3043900E02B93 /* machineLearning.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = machineLearning.cpp; sourceTree = "<group>"; }; + 1A00309A1FC3043900E02B93 /* machineLearning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = machineLearning.h; sourceTree = "<group>"; }; + 1A00309C1FC3043900E02B93 /* rapidGVF.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rapidGVF.cpp; sourceTree = "<group>"; }; + 1A00309D1FC3043900E02B93 /* rapidGVF.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rapidGVF.h; sourceTree = "<group>"; }; + 1A00309F1FC3043900E02B93 /* rapidXMM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rapidXMM.cpp; sourceTree = "<group>"; }; + 1A0030A01FC3043900E02B93 /* rapidXMM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rapidXMM.h; sourceTree = "<group>"; }; + 1A0030A11FC3043900E02B93 /* trainingData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = trainingData.cpp; sourceTree = "<group>"; }; + 1A0030A21FC3043900E02B93 /* trainingData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = trainingData.h; sourceTree = "<group>"; }; + 1A0030A31FC3043900E02B93 /* rapidmix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rapidmix.h; sourceTree = "<group>"; }; + 1A0030A61FC3043900E02B93 /* rapidPiPoHost.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rapidPiPoHost.cpp; sourceTree = "<group>"; }; + 1A0030A71FC3043900E02B93 /* rapidPiPoHost.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rapidPiPoHost.h; sourceTree = "<group>"; }; + 1A0030A81FC3043900E02B93 /* rapidPiPoTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rapidPiPoTools.h; sourceTree = "<group>"; }; + 1A0030A91FC3043900E02B93 /* signalProcessing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = signalProcessing.h; sourceTree = "<group>"; }; + 1A04D8C21FC31C0000D725DC /* RapidBitalino.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RapidBitalino.h; sourceTree = "<group>"; }; + 1A04D8C31FC31D0E00D725DC /* RapidBitalino.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RapidBitalino.cpp; sourceTree = "<group>"; }; + 1A04D8D71FC38F3700D725DC /* libRAPID-MIX_API.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libRAPID-MIX_API.a"; sourceTree = "<group>"; }; + 1A7329411FC30563001E730B /* GVF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GVF.cpp; sourceTree = "<group>"; }; + 1A7329421FC30563001E730B /* GVF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GVF.h; sourceTree = "<group>"; }; + 1A7329431FC30563001E730B /* GVFGesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GVFGesture.h; sourceTree = "<group>"; }; + 1A7329441FC30563001E730B /* GVFUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GVFUtils.h; sourceTree = "<group>"; }; + 1A7329451FC30563001E730B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; + 1A732AFD1FC30563001E730B /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; }; + 1A732B001FC30563001E730B /* libpipo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libpipo.a; sourceTree = "<group>"; }; + 1A732B301FC30563001E730B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; }; + 1A732B341FC30563001E730B /* BayesianFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BayesianFilter.cpp; sourceTree = "<group>"; }; + 1A732B351FC30563001E730B /* BayesianFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BayesianFilter.h; sourceTree = "<group>"; }; + 1A732B361FC30563001E730B /* filter_utilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filter_utilities.cpp; sourceTree = "<group>"; }; + 1A732B371FC30563001E730B /* filter_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filter_utilities.h; sourceTree = "<group>"; }; + 1A732B391FC30563001E730B /* finitedifferences.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = finitedifferences.c; sourceTree = "<group>"; }; + 1A732B3A1FC30563001E730B /* finitedifferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = finitedifferences.h; sourceTree = "<group>"; }; + 1A732B3C1FC30563001E730B /* bbpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bbpr.cpp; sourceTree = "<group>"; }; + 1A732B3D1FC30563001E730B /* bbpr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bbpr.h; sourceTree = "<group>"; }; + 1A732B3E1FC30563001E730B /* rpoly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rpoly.cpp; sourceTree = "<group>"; }; + 1A732B3F1FC30563001E730B /* rpoly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rpoly.h; sourceTree = "<group>"; }; + 1A732B421FC30563001E730B /* rta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta.h; sourceTree = "<group>"; }; + 1A732B431FC30563001E730B /* rta_bpf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_bpf.c; sourceTree = "<group>"; }; + 1A732B441FC30563001E730B /* rta_bpf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_bpf.h; sourceTree = "<group>"; }; + 1A732B451FC30563001E730B /* rta_complex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_complex.h; sourceTree = "<group>"; }; + 1A732B461FC30563001E730B /* rta_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_float.h; sourceTree = "<group>"; }; + 1A732B471FC30563001E730B /* rta_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_int.c; sourceTree = "<group>"; }; + 1A732B481FC30563001E730B /* rta_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_int.h; sourceTree = "<group>"; }; + 1A732B491FC30563001E730B /* rta_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_math.h; sourceTree = "<group>"; }; + 1A732B4A1FC30563001E730B /* rta_stdio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_stdio.h; sourceTree = "<group>"; }; + 1A732B4B1FC30563001E730B /* rta_stdlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_stdlib.h; sourceTree = "<group>"; }; + 1A732B4C1FC30563001E730B /* rta_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_types.h; sourceTree = "<group>"; }; + 1A732B4D1FC30563001E730B /* rta_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_util.c; sourceTree = "<group>"; }; + 1A732B4E1FC30563001E730B /* rta_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_util.h; sourceTree = "<group>"; }; + 1A732B501FC30563001E730B /* rta_bands.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_bands.c; sourceTree = "<group>"; }; + 1A732B511FC30563001E730B /* rta_bands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_bands.h; sourceTree = "<group>"; }; + 1A732B521FC30563001E730B /* rta_biquad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_biquad.c; sourceTree = "<group>"; }; + 1A732B531FC30563001E730B /* rta_biquad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_biquad.h; sourceTree = "<group>"; }; + 1A732B541FC30563001E730B /* rta_correlation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_correlation.c; sourceTree = "<group>"; }; + 1A732B551FC30563001E730B /* rta_correlation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_correlation.h; sourceTree = "<group>"; }; + 1A732B561FC30563001E730B /* rta_cubic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_cubic.c; sourceTree = "<group>"; }; + 1A732B571FC30563001E730B /* rta_cubic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_cubic.h; sourceTree = "<group>"; }; + 1A732B581FC30563001E730B /* rta_dct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_dct.c; sourceTree = "<group>"; }; + 1A732B591FC30563001E730B /* rta_dct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_dct.h; sourceTree = "<group>"; }; + 1A732B5A1FC30563001E730B /* rta_delta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_delta.c; sourceTree = "<group>"; }; + 1A732B5B1FC30563001E730B /* rta_delta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_delta.h; sourceTree = "<group>"; }; + 1A732B5C1FC30563001E730B /* rta_fft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_fft.c; sourceTree = "<group>"; }; + 1A732B5D1FC30563001E730B /* rta_fft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_fft.h; sourceTree = "<group>"; }; + 1A732B5E1FC30563001E730B /* rta_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_filter.h; sourceTree = "<group>"; }; + 1A732B5F1FC30563001E730B /* rta_lifter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_lifter.c; sourceTree = "<group>"; }; + 1A732B601FC30563001E730B /* rta_lifter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_lifter.h; sourceTree = "<group>"; }; + 1A732B611FC30563001E730B /* rta_lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_lpc.c; sourceTree = "<group>"; }; + 1A732B621FC30563001E730B /* rta_lpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_lpc.h; sourceTree = "<group>"; }; + 1A732B631FC30563001E730B /* rta_mean_variance.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_mean_variance.c; sourceTree = "<group>"; }; + 1A732B641FC30563001E730B /* rta_mean_variance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_mean_variance.h; sourceTree = "<group>"; }; + 1A732B651FC30563001E730B /* rta_mel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_mel.c; sourceTree = "<group>"; }; + 1A732B661FC30563001E730B /* rta_mel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_mel.h; sourceTree = "<group>"; }; + 1A732B671FC30563001E730B /* rta_moments.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_moments.c; sourceTree = "<group>"; }; + 1A732B681FC30563001E730B /* rta_moments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_moments.h; sourceTree = "<group>"; }; + 1A732B691FC30563001E730B /* rta_onepole.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_onepole.c; sourceTree = "<group>"; }; + 1A732B6A1FC30563001E730B /* rta_onepole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_onepole.h; sourceTree = "<group>"; }; + 1A732B6B1FC30563001E730B /* rta_preemphasis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_preemphasis.c; sourceTree = "<group>"; }; + 1A732B6C1FC30563001E730B /* rta_preemphasis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_preemphasis.h; sourceTree = "<group>"; }; + 1A732B6D1FC30563001E730B /* rta_resample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_resample.c; sourceTree = "<group>"; }; + 1A732B6E1FC30563001E730B /* rta_resample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_resample.h; sourceTree = "<group>"; }; + 1A732B6F1FC30563001E730B /* rta_selection.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_selection.c; sourceTree = "<group>"; }; + 1A732B701FC30563001E730B /* rta_selection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_selection.h; sourceTree = "<group>"; }; + 1A732B711FC30563001E730B /* rta_svd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_svd.c; sourceTree = "<group>"; }; + 1A732B721FC30563001E730B /* rta_svd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_svd.h; sourceTree = "<group>"; }; + 1A732B731FC30563001E730B /* rta_window.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rta_window.c; sourceTree = "<group>"; }; + 1A732B741FC30563001E730B /* rta_window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_window.h; sourceTree = "<group>"; }; + 1A732B751FC30563001E730B /* rta_configuration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rta_configuration.h; sourceTree = "<group>"; }; + 1A732B771FC30563001E730B /* mimo_host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mimo_host.h; sourceTree = "<group>"; }; + 1A732B781FC30563001E730B /* PiPoCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PiPoCollection.cpp; sourceTree = "<group>"; }; + 1A732B791FC30563001E730B /* PiPoCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoCollection.h; sourceTree = "<group>"; }; + 1A732B7A1FC30563001E730B /* PiPoGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoGraph.h; sourceTree = "<group>"; }; + 1A732B7B1FC30563001E730B /* PiPoHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoHost.h; sourceTree = "<group>"; }; + 1A732B7C1FC30563001E730B /* PiPoModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoModule.h; sourceTree = "<group>"; }; + 1A732B7E1FC30563001E730B /* mimo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mimo.h; sourceTree = "<group>"; }; + 1A732B7F1FC30563001E730B /* PiPo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPo.h; sourceTree = "<group>"; }; + 1A732B801FC30563001E730B /* PiPoParallel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoParallel.h; sourceTree = "<group>"; }; + 1A732B811FC30563001E730B /* PiPoSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoSequence.h; sourceTree = "<group>"; }; + 1A732B821FC30563001E730B /* RingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RingBuffer.h; sourceTree = "<group>"; }; + 1A732B851FC30563001E730B /* mimo_stats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mimo_stats.h; sourceTree = "<group>"; }; + 1A732B861FC30563001E730B /* PiPoBands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoBands.h; sourceTree = "<group>"; }; + 1A732B871FC30563001E730B /* PiPoBayesFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoBayesFilter.h; sourceTree = "<group>"; }; + 1A732B881FC30563001E730B /* PiPoBiquad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoBiquad.h; sourceTree = "<group>"; }; + 1A732B891FC30563001E730B /* PiPoChop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoChop.h; sourceTree = "<group>"; }; + 1A732B8A1FC30563001E730B /* PiPoConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoConst.h; sourceTree = "<group>"; }; + 1A732B8B1FC30563001E730B /* PiPoDct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoDct.h; sourceTree = "<group>"; }; + 1A732B8C1FC30563001E730B /* PiPoDelta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoDelta.h; sourceTree = "<group>"; }; + 1A732B8D1FC30563001E730B /* PiPoFft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoFft.h; sourceTree = "<group>"; }; + 1A732B8E1FC30563001E730B /* PiPoFiniteDif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoFiniteDif.h; sourceTree = "<group>"; }; + 1A732B8F1FC30563001E730B /* PiPoGate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoGate.h; sourceTree = "<group>"; }; + 1A732B901FC30563001E730B /* PiPoLpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoLpc.h; sourceTree = "<group>"; }; + 1A732B911FC30563001E730B /* PiPoLpcFormants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoLpcFormants.h; sourceTree = "<group>"; }; + 1A732B921FC30563001E730B /* PiPoMeanStddev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMeanStddev.h; sourceTree = "<group>"; }; + 1A732B931FC30563001E730B /* PiPoMedian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMedian.h; sourceTree = "<group>"; }; + 1A732B941FC30563001E730B /* PiPoMel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMel.h; sourceTree = "<group>"; }; + 1A732B951FC30563001E730B /* PiPoMfcc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMfcc.h; sourceTree = "<group>"; }; + 1A732B961FC30563001E730B /* PiPoMinMax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMinMax.h; sourceTree = "<group>"; }; + 1A732B971FC30563001E730B /* PiPoMoments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMoments.h; sourceTree = "<group>"; }; + 1A732B981FC30563001E730B /* PiPoMvavrg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoMvavrg.h; sourceTree = "<group>"; }; + 1A732B991FC30563001E730B /* PiPoOnseg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoOnseg.h; sourceTree = "<group>"; }; + 1A732B9A1FC30563001E730B /* PiPoPeaks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoPeaks.h; sourceTree = "<group>"; }; + 1A732B9B1FC30563001E730B /* PiPoRms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoRms.h; sourceTree = "<group>"; }; + 1A732B9C1FC30563001E730B /* PiPoScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoScale.h; sourceTree = "<group>"; }; + 1A732B9D1FC30563001E730B /* PiPoSelect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoSelect.h; sourceTree = "<group>"; }; + 1A732B9E1FC30563001E730B /* PiPoSlice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoSlice.h; sourceTree = "<group>"; }; + 1A732B9F1FC30563001E730B /* PiPoSum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiPoSum.h; sourceTree = "<group>"; }; + 1A732BA01FC30563001E730B /* TempMod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TempMod.h; sourceTree = "<group>"; }; + 1A732BB11FC30563001E730B /* json-forwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "json-forwards.h"; sourceTree = "<group>"; }; + 1A732BB21FC30563001E730B /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; }; + 1A732BB31FC30563001E730B /* jsoncpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsoncpp.cpp; sourceTree = "<group>"; }; + 1A732BB51FC30563001E730B /* libsvm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libsvm.cpp; sourceTree = "<group>"; }; + 1A732BB61FC30563001E730B /* libsvm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libsvm.h; sourceTree = "<group>"; }; + 1A732E871FC30565001E730B /* baseModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = baseModel.h; sourceTree = "<group>"; }; + 1A732E881FC30565001E730B /* classification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = classification.cpp; sourceTree = "<group>"; }; + 1A732E891FC30565001E730B /* classification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = classification.h; sourceTree = "<group>"; }; + 1A732E8A1FC30565001E730B /* dtw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtw.cpp; sourceTree = "<group>"; }; + 1A732E8B1FC30565001E730B /* dtw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtw.h; sourceTree = "<group>"; }; + 1A732E8D1FC30565001E730B /* classificationEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = classificationEmbindings.h; sourceTree = "<group>"; }; + 1A732E8E1FC30565001E730B /* knnEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = knnEmbindings.h; sourceTree = "<group>"; }; + 1A732E8F1FC30565001E730B /* modelSetEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modelSetEmbindings.h; sourceTree = "<group>"; }; + 1A732E901FC30565001E730B /* nnEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nnEmbindings.h; sourceTree = "<group>"; }; + 1A732E911FC30565001E730B /* nodeEnv.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = nodeEnv.js; sourceTree = "<group>"; }; + 1A732E921FC30565001E730B /* rapidLibPost.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = rapidLibPost.js; sourceTree = "<group>"; }; + 1A732E931FC30565001E730B /* rapidStreamEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rapidStreamEmbindings.h; sourceTree = "<group>"; }; + 1A732E941FC30565001E730B /* regressionEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = regressionEmbindings.h; sourceTree = "<group>"; }; + 1A732E951FC30565001E730B /* seriesClassificationEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seriesClassificationEmbindings.h; sourceTree = "<group>"; }; + 1A732E961FC30565001E730B /* svmEmbindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svmEmbindings.h; sourceTree = "<group>"; }; + 1A732E971FC30565001E730B /* fastDTW.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fastDTW.cpp; sourceTree = "<group>"; }; + 1A732E981FC30565001E730B /* fastDTW.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fastDTW.h; sourceTree = "<group>"; }; + 1A732E991FC30565001E730B /* knnClassification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = knnClassification.cpp; sourceTree = "<group>"; }; + 1A732E9A1FC30565001E730B /* knnClassification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = knnClassification.h; sourceTree = "<group>"; }; + 1A732E9B1FC30565001E730B /* modelSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = modelSet.cpp; sourceTree = "<group>"; }; + 1A732E9C1FC30565001E730B /* modelSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modelSet.h; sourceTree = "<group>"; }; + 1A732E9D1FC30565001E730B /* neuralNetwork.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = neuralNetwork.cpp; sourceTree = "<group>"; }; + 1A732E9E1FC30565001E730B /* neuralNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = neuralNetwork.h; sourceTree = "<group>"; }; + 1A732E9F1FC30565001E730B /* rapidStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rapidStream.cpp; sourceTree = "<group>"; }; + 1A732EA01FC30565001E730B /* rapidStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rapidStream.h; sourceTree = "<group>"; }; + 1A732EA11FC30565001E730B /* regression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = regression.cpp; sourceTree = "<group>"; }; + 1A732EA21FC30565001E730B /* regression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = regression.h; sourceTree = "<group>"; }; + 1A732EA31FC30565001E730B /* searchWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = searchWindow.cpp; sourceTree = "<group>"; }; + 1A732EA41FC30565001E730B /* searchWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = searchWindow.h; sourceTree = "<group>"; }; + 1A732EA51FC30565001E730B /* seriesClassification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seriesClassification.cpp; sourceTree = "<group>"; }; + 1A732EA61FC30565001E730B /* seriesClassification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seriesClassification.h; sourceTree = "<group>"; }; + 1A732EA71FC30565001E730B /* svmClassification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = svmClassification.cpp; sourceTree = "<group>"; }; + 1A732EA81FC30565001E730B /* svmClassification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svmClassification.h; sourceTree = "<group>"; }; + 1A732EA91FC30565001E730B /* trainingExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trainingExample.h; sourceTree = "<group>"; }; + 1A732EAA1FC30565001E730B /* warpPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = warpPath.cpp; sourceTree = "<group>"; }; + 1A732EAB1FC30565001E730B /* warpPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = warpPath.h; sourceTree = "<group>"; }; + 1A732EC21FC30565001E730B /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch.hpp; sourceTree = "<group>"; }; + 1A732EC31FC30565001E730B /* LICENSE_1_0.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE_1_0.txt; sourceTree = "<group>"; }; + 1A732EC51FC30565001E730B /* json-forwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "json-forwards.h"; sourceTree = "<group>"; }; + 1A732EC61FC30565001E730B /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; }; + 1A732EC71FC30565001E730B /* jsoncpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsoncpp.cpp; sourceTree = "<group>"; }; + 1A732EC91FC30565001E730B /* libsvm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libsvm.cpp; sourceTree = "<group>"; }; + 1A732ECA1FC30565001E730B /* libsvm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libsvm.h; sourceTree = "<group>"; }; + 1A732ECB1FC30565001E730B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; + 1A732ECD1FC30565001E730B /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; }; + 1A732ECE1FC30565001E730B /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; + 1A732ED11FC30565001E730B /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch.hpp; sourceTree = "<group>"; }; + 1A732ED41FC30565001E730B /* assertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assertions.h; sourceTree = "<group>"; }; + 1A732ED51FC30565001E730B /* autolink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autolink.h; sourceTree = "<group>"; }; + 1A732ED61FC30565001E730B /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; }; + 1A732ED71FC30565001E730B /* forwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = forwards.h; sourceTree = "<group>"; }; + 1A732ED81FC30565001E730B /* json-features.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "json-features.h"; sourceTree = "<group>"; }; + 1A732ED91FC30565001E730B /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; }; + 1A732EDA1FC30565001E730B /* reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reader.h; sourceTree = "<group>"; }; + 1A732EDB1FC30565001E730B /* value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = value.h; sourceTree = "<group>"; }; + 1A732EDC1FC30565001E730B /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; }; + 1A732EDD1FC30565001E730B /* writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = writer.h; sourceTree = "<group>"; }; + 1A732EDE1FC30565001E730B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; + 1A732EE01FC30565001E730B /* json_reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_reader.cpp; sourceTree = "<group>"; }; + 1A732EE11FC30565001E730B /* json_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_tool.h; sourceTree = "<group>"; }; + 1A732EE21FC30565001E730B /* json_value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_value.cpp; sourceTree = "<group>"; }; + 1A732EE31FC30565001E730B /* json_valueiterator.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = json_valueiterator.inl; sourceTree = "<group>"; }; + 1A732EE41FC30565001E730B /* json_writer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_writer.cpp; sourceTree = "<group>"; }; + 1A732EE71FC30565001E730B /* footer.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = footer.html; sourceTree = "<group>"; }; + 1A732EE81FC30565001E730B /* header.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = header.html; sourceTree = "<group>"; }; + 1A732EE91FC30565001E730B /* jdoxygen.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = jdoxygen.css; sourceTree = "<group>"; }; + 1A732EEA1FC30565001E730B /* jtabs.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = jtabs.css; sourceTree = "<group>"; }; + 1A732EEB1FC30565001E730B /* python_example.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = python_example.py; sourceTree = "<group>"; }; + 1A732EEC1FC30565001E730B /* QuickStart_Python.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = QuickStart_Python.html; sourceTree = "<group>"; }; + 1A732EED1FC30565001E730B /* xmm_architecture.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = xmm_architecture.jpg; sourceTree = "<group>"; }; + 1A732EEE1FC30565001E730B /* xmm_featured.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = xmm_featured.jpg; sourceTree = "<group>"; }; + 1A732EEF1FC30565001E730B /* xmm_featured_.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = xmm_featured_.jpg; sourceTree = "<group>"; }; + 1A732EF01FC30565001E730B /* xmm_models.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = xmm_models.jpg; sourceTree = "<group>"; }; + 1A732EF11FC30565001E730B /* XmmDoxygenLayout.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = XmmDoxygenLayout.xml; sourceTree = "<group>"; }; + 1A732EF21FC30565001E730B /* Doxyfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Doxyfile; sourceTree = "<group>"; }; + 1A732EF31FC30565001E730B /* Doxyfile-dot */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Doxyfile-dot"; sourceTree = "<group>"; }; + 1A732EF91FC30565001E730B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; + 1A732F121FC30565001E730B /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = "<group>"; }; + 1A732F161FC30565001E730B /* xmmAttribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmAttribute.cpp; sourceTree = "<group>"; }; + 1A732F171FC30565001E730B /* xmmAttribute.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmAttribute.hpp; sourceTree = "<group>"; }; + 1A732F181FC30565001E730B /* xmmCircularbuffer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmCircularbuffer.hpp; sourceTree = "<group>"; }; + 1A732F191FC30565001E730B /* xmmEvents.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmEvents.hpp; sourceTree = "<group>"; }; + 1A732F1A1FC30565001E730B /* xmmJson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmJson.cpp; sourceTree = "<group>"; }; + 1A732F1B1FC30565001E730B /* xmmJson.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmJson.hpp; sourceTree = "<group>"; }; + 1A732F1C1FC30565001E730B /* xmmMatrix.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmMatrix.hpp; sourceTree = "<group>"; }; + 1A732F1E1FC30565001E730B /* xmmGaussianDistribution.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmGaussianDistribution.cpp; sourceTree = "<group>"; }; + 1A732F1F1FC30565001E730B /* xmmGaussianDistribution.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmGaussianDistribution.hpp; sourceTree = "<group>"; }; + 1A732F211FC30565001E730B /* xmmModel.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmModel.hpp; sourceTree = "<group>"; }; + 1A732F221FC30565001E730B /* xmmModelConfiguration.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmModelConfiguration.hpp; sourceTree = "<group>"; }; + 1A732F231FC30565001E730B /* xmmModelParameters.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmModelParameters.hpp; sourceTree = "<group>"; }; + 1A732F241FC30565001E730B /* xmmModelResults.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmModelResults.hpp; sourceTree = "<group>"; }; + 1A732F251FC30565001E730B /* xmmModelSharedParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmModelSharedParameters.cpp; sourceTree = "<group>"; }; + 1A732F261FC30565001E730B /* xmmModelSharedParameters.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmModelSharedParameters.hpp; sourceTree = "<group>"; }; + 1A732F271FC30565001E730B /* xmmModelSingleClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmModelSingleClass.cpp; sourceTree = "<group>"; }; + 1A732F281FC30565001E730B /* xmmModelSingleClass.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmModelSingleClass.hpp; sourceTree = "<group>"; }; + 1A732F2A1FC30565001E730B /* xmmPhrase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmPhrase.cpp; sourceTree = "<group>"; }; + 1A732F2B1FC30565001E730B /* xmmPhrase.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmPhrase.hpp; sourceTree = "<group>"; }; + 1A732F2C1FC30565001E730B /* xmmTrainingSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmTrainingSet.cpp; sourceTree = "<group>"; }; + 1A732F2D1FC30565001E730B /* xmmTrainingSet.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmTrainingSet.hpp; sourceTree = "<group>"; }; + 1A732F301FC30565001E730B /* xmmGmm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmGmm.cpp; sourceTree = "<group>"; }; + 1A732F311FC30565001E730B /* xmmGmm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmGmm.hpp; sourceTree = "<group>"; }; + 1A732F321FC30565001E730B /* xmmGmmParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmGmmParameters.cpp; sourceTree = "<group>"; }; + 1A732F331FC30565001E730B /* xmmGmmParameters.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmGmmParameters.hpp; sourceTree = "<group>"; }; + 1A732F341FC30565001E730B /* xmmGmmSingleClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmGmmSingleClass.cpp; sourceTree = "<group>"; }; + 1A732F351FC30565001E730B /* xmmGmmSingleClass.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmGmmSingleClass.hpp; sourceTree = "<group>"; }; + 1A732F371FC30565001E730B /* xmmHierarchicalHmm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmHierarchicalHmm.cpp; sourceTree = "<group>"; }; + 1A732F381FC30565001E730B /* xmmHierarchicalHmm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmHierarchicalHmm.hpp; sourceTree = "<group>"; }; + 1A732F391FC30565001E730B /* xmmHmmParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmHmmParameters.cpp; sourceTree = "<group>"; }; + 1A732F3A1FC30565001E730B /* xmmHmmParameters.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmHmmParameters.hpp; sourceTree = "<group>"; }; + 1A732F3B1FC30565001E730B /* xmmHmmResults.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmHmmResults.hpp; sourceTree = "<group>"; }; + 1A732F3C1FC30565001E730B /* xmmHmmSingleClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmHmmSingleClass.cpp; sourceTree = "<group>"; }; + 1A732F3D1FC30565001E730B /* xmmHmmSingleClass.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmHmmSingleClass.hpp; sourceTree = "<group>"; }; + 1A732F3F1FC30565001E730B /* xmmKMeans.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmKMeans.cpp; sourceTree = "<group>"; }; + 1A732F401FC30565001E730B /* xmmKMeans.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmKMeans.hpp; sourceTree = "<group>"; }; + 1A732F411FC30565001E730B /* xmmKMeansParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmmKMeansParameters.cpp; sourceTree = "<group>"; }; + 1A732F421FC30565001E730B /* xmmKMeansParameters.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmKMeansParameters.hpp; sourceTree = "<group>"; }; + 1A732F431FC30565001E730B /* xmmKMeansResults.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xmmKMeansResults.hpp; sourceTree = "<group>"; }; + 1A732F441FC30565001E730B /* xmm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xmm.h; sourceTree = "<group>"; }; + 1AF8F4F21FBFBA56007845B3 /* bitalino.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bitalino.cpp; sourceTree = "<group>"; }; + 1AF8F4F31FBFBA56007845B3 /* bitalino.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitalino.h; sourceTree = "<group>"; }; + 1AF8F4FD1FC0D5C6007845B3 /* RingBuffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RingBuffer.hpp; sourceTree = "<group>"; }; + 1AF8F4FF1FC106D2007845B3 /* ThreadedProcess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadedProcess.h; sourceTree = "<group>"; }; + 1AF8F5001FC108DE007845B3 /* BitalinoThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitalinoThread.h; sourceTree = "<group>"; }; + 1AFD55011FC1C73500BDC5EC /* RapidMixThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RapidMixThread.h; sourceTree = "<group>"; }; + 21080C6D8829F198543F568E /* maxiAtoms.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = maxiAtoms.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiAtoms.cpp; sourceTree = SOURCE_ROOT; }; + 283D3449127FCD4AE5F47F88 /* ofxBaseGui.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxBaseGui.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxBaseGui.cpp; sourceTree = SOURCE_ROOT; }; + 2E39787D52B2DB29CF1FCF66 /* IpEndpointName.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = IpEndpointName.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.h; sourceTree = SOURCE_ROOT; }; + 300B4DCCFFECBD546568227A /* maxiGrains.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = maxiGrains.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiGrains.cpp; sourceTree = SOURCE_ROOT; }; + 333B161A45E42EF09ADEC7A5 /* OscReceivedElements.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = OscReceivedElements.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.cpp; sourceTree = SOURCE_ROOT; }; + 33C51958AA0CAE4F88D953DC /* ofxOsc.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOsc.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOsc.h; sourceTree = SOURCE_ROOT; }; + 3646FFD002EE9FED0DD367F3 /* ofxPanel.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxPanel.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxPanel.cpp; sourceTree = SOURCE_ROOT; }; + 3A6FBE64E557C85D306947E4 /* ofxBaseGui.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxBaseGui.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxBaseGui.h; sourceTree = SOURCE_ROOT; }; + 3B129EA9D541BE47A473BC06 /* maxiFFT.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = maxiFFT.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiFFT.h; sourceTree = SOURCE_ROOT; }; + 3F1F7648BBA70B28FE923560 /* sineTable.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = sineTable.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/sineTable.h; sourceTree = SOURCE_ROOT; }; + 4169271F18AE49EFC953B0AB /* ofxLabel.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxLabel.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxLabel.h; sourceTree = SOURCE_ROOT; }; + 43AF2D57607DD0B4AF3A6183 /* fft.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = fft.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/fft.h; sourceTree = SOURCE_ROOT; }; + 47DFCF539679C49445A74E64 /* OscTypes.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscTypes.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.h; sourceTree = SOURCE_ROOT; }; + 4A2FCA86040F43BCB2C12BCA /* ofxButton.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxButton.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxButton.h; sourceTree = SOURCE_ROOT; }; + 5065E0436E391619A021DE76 /* NetworkingUtils.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = NetworkingUtils.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/NetworkingUtils.h; sourceTree = SOURCE_ROOT; }; + 50B91A7EB2184FD67A06D044 /* maxiBark.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = maxiBark.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiBark.h; sourceTree = SOURCE_ROOT; }; + 54C5AF569662A8351667313E /* NetworkingUtils.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = NetworkingUtils.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/posix/NetworkingUtils.cpp; sourceTree = SOURCE_ROOT; }; + 552D90E7024A93518E711979 /* IpEndpointName.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = IpEndpointName.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.cpp; sourceTree = SOURCE_ROOT; }; + 57C2E0F28BA237CECA2DD2F3 /* stb_vorbis.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = stb_vorbis.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/stb_vorbis.h; sourceTree = SOURCE_ROOT; }; + 5BA6903E0287C0B3CBF81989 /* ofxToggle.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxToggle.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxToggle.cpp; sourceTree = SOURCE_ROOT; }; + 5D3DC557A3FD0ADFC8D06276 /* ofxOscParameterSync.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOscParameterSync.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscParameterSync.h; sourceTree = SOURCE_ROOT; }; + 6107D0B5FEEE887645CC8673 /* OscReceivedElements.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscReceivedElements.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.h; sourceTree = SOURCE_ROOT; }; + 6D68865B98C85481FB07D746 /* ofxOscBundle.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOscBundle.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscBundle.h; sourceTree = SOURCE_ROOT; }; + 6D7D4C890B7E7E86CF67EDE9 /* maxiFFT.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = maxiFFT.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiFFT.cpp; sourceTree = SOURCE_ROOT; }; + 6EFE170390703388444A995C /* OscPrintReceivedElements.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = OscPrintReceivedElements.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscPrintReceivedElements.cpp; sourceTree = SOURCE_ROOT; }; + 771343C29ADB1A34A5E3F2D7 /* OscOutboundPacketStream.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscOutboundPacketStream.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.h; sourceTree = SOURCE_ROOT; }; + 7805756184CF7E3670EBA6B9 /* OscPacketListener.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscPacketListener.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscPacketListener.h; sourceTree = SOURCE_ROOT; }; + 7FDED04B5307798C8725EDDE /* OscHostEndianness.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscHostEndianness.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscHostEndianness.h; sourceTree = SOURCE_ROOT; }; + 86ECBAD17F7B1D927CB1931F /* ofxPanel.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxPanel.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxPanel.h; sourceTree = SOURCE_ROOT; }; + 8DC5D79A78655BF028FBDE30 /* stb_vorbis.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 30; name = stb_vorbis.c; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/stb_vorbis.c; sourceTree = SOURCE_ROOT; }; + 8F5FFC9C08A87AE48EA5E66C /* ofxOscReceiver.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxOscReceiver.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscReceiver.cpp; sourceTree = SOURCE_ROOT; }; + 951C54CCCD72A0FFC773653F /* ofxSlider.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxSlider.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxSlider.cpp; sourceTree = SOURCE_ROOT; }; + A93736CA5EE7029E798A22AA /* ofxMaxim.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxMaxim.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/src/ofxMaxim.h; sourceTree = SOURCE_ROOT; }; + AA63660625DF3459DBD8486C /* OscPrintReceivedElements.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscPrintReceivedElements.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscPrintReceivedElements.h; sourceTree = SOURCE_ROOT; }; + AEC6D21EB03AE1B72B35D0D9 /* ofxOscSender.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxOscSender.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscSender.cpp; sourceTree = SOURCE_ROOT; }; + B86B7BDD7ADBAB228DB14744 /* ofxSliderGroup.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxSliderGroup.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxSliderGroup.h; sourceTree = SOURCE_ROOT; }; + C00AD5B8094B3634B06C5926 /* ofxToggle.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxToggle.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxToggle.h; sourceTree = SOURCE_ROOT; }; + C590EAED7C04204257DE2745 /* maxiMFCC.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = maxiMFCC.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiMFCC.cpp; sourceTree = SOURCE_ROOT; }; + C85AEC4A09E7407508E41723 /* ofxLabel.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxLabel.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxLabel.cpp; sourceTree = SOURCE_ROOT; }; + D39514497AFC9A4AAE903696 /* ofxOscMessage.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxOscMessage.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscMessage.cpp; sourceTree = SOURCE_ROOT; }; + D6A1246E09C6B8CDA06EEC4F /* OscException.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = OscException.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscException.h; sourceTree = SOURCE_ROOT; }; + D9460E080AF572AB4FE572C2 /* ofxGui.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxGui.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxGui.h; sourceTree = SOURCE_ROOT; }; + DC8DE4E32DB58B5849214F05 /* fft.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = fft.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/fft.cpp; sourceTree = SOURCE_ROOT; }; + DCB987CA7BF7FB3A39EF3514 /* ofxOscParameterSync.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxOscParameterSync.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscParameterSync.cpp; sourceTree = SOURCE_ROOT; }; + DD3E35208D66CC444D100690 /* UdpSocket.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = UdpSocket.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/UdpSocket.h; sourceTree = SOURCE_ROOT; }; + DE6FBA724BBE5D9249AC3BCF /* ofxOscArg.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOscArg.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscArg.h; sourceTree = SOURCE_ROOT; }; + E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = openFrameworksLib.xcodeproj; path = ../../../../../Documents/of_v0.9.8_osx_release/libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj; sourceTree = SOURCE_ROOT; }; + E4B69B5B0A3A1756003C02F2 /* BitalinoDebug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BitalinoDebug.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E4B69E1D0A3A1BDC003C02F2 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = src/main.cpp; sourceTree = SOURCE_ROOT; }; + E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofApp.cpp; path = src/ofApp.cpp; sourceTree = SOURCE_ROOT; }; + E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ofApp.h; path = src/ofApp.h; sourceTree = SOURCE_ROOT; }; + E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = "openFrameworks-Info.plist"; sourceTree = "<group>"; }; + E4EB691F138AFCF100A09F29 /* CoreOF.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CoreOF.xcconfig; path = ../../../../../Documents/of_v0.9.8_osx_release/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig; sourceTree = SOURCE_ROOT; }; + E4EB6923138AFD0F00A09F29 /* Project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Project.xcconfig; sourceTree = "<group>"; }; + E661ACAA5BEC5B96FD2F6532 /* ofxSliderGroup.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxSliderGroup.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxSliderGroup.cpp; sourceTree = SOURCE_ROOT; }; + E76982C6091099847AF4A689 /* ofxButton.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofxButton.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxButton.cpp; sourceTree = SOURCE_ROOT; }; + E79D78A192005C0D7FDA98C0 /* maxiBark.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = maxiBark.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiBark.cpp; sourceTree = SOURCE_ROOT; }; + E808847ECDCE62ABFF8D5E4D /* maxiGrains.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = maxiGrains.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiGrains.h; sourceTree = SOURCE_ROOT; }; + E87C4F253FACA6BBF714AD99 /* OscTypes.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = OscTypes.cpp; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.cpp; sourceTree = SOURCE_ROOT; }; + EB00468633B458B3AF898FAC /* maxiAtoms.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = maxiAtoms.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiAtoms.h; sourceTree = SOURCE_ROOT; }; + F0448463C9530F4935705C48 /* MessageMappingOscPacketListener.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = MessageMappingOscPacketListener.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc/MessageMappingOscPacketListener.h; sourceTree = SOURCE_ROOT; }; + F0DBD3DF50BD6761963D69B6 /* ofxOscMessage.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOscMessage.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscMessage.h; sourceTree = SOURCE_ROOT; }; + F4750E6716D760CCBF1143CF /* ofxGuiGroup.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxGuiGroup.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxGuiGroup.h; sourceTree = SOURCE_ROOT; }; + F890C575BD59092852BD3CB2 /* ofxSlider.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxSlider.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src/ofxSlider.h; sourceTree = SOURCE_ROOT; }; + FC08FD52F6639D7D5EC893D6 /* maxiMFCC.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = maxiMFCC.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs/maxiMFCC.h; sourceTree = SOURCE_ROOT; }; + FCCD68796F8A249EA9FEDD44 /* ofxOscSender.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxOscSender.h; path = ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src/ofxOscSender.h; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E4B69B590A3A1756003C02F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E4328149138ABC9F0047C5CB /* openFrameworksDebug.a in Frameworks */, + 1A04D8D81FC38F3700D725DC /* libRAPID-MIX_API.a in Frameworks */, + 1A732FC91FC30566001E730B /* libpipo.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1A002A861FC303F700E02B93 /* Rapid-Mix */ = { + isa = PBXGroup; + children = ( + 1A73293F1FC30563001E730B /* dependencies */, + 1A0030961FC3043900E02B93 /* rapid-mix */, + ); + name = "Rapid-Mix"; + sourceTree = "<group>"; + }; + 1A0030961FC3043900E02B93 /* rapid-mix */ = { + isa = PBXGroup; + children = ( + 1A0030971FC3043900E02B93 /* LICENSE */, + 1A0030981FC3043900E02B93 /* machineLearning */, + 1A0030A31FC3043900E02B93 /* rapidmix.h */, + 1A0030A41FC3043900E02B93 /* signalProcessing */, + ); + path = "rapid-mix"; + sourceTree = "<group>"; + }; + 1A0030981FC3043900E02B93 /* machineLearning */ = { + isa = PBXGroup; + children = ( + 1A0030991FC3043900E02B93 /* machineLearning.cpp */, + 1A00309A1FC3043900E02B93 /* machineLearning.h */, + 1A00309B1FC3043900E02B93 /* rapidGVF */, + 1A00309E1FC3043900E02B93 /* rapidXMM */, + 1A0030A11FC3043900E02B93 /* trainingData.cpp */, + 1A0030A21FC3043900E02B93 /* trainingData.h */, + ); + path = machineLearning; + sourceTree = "<group>"; + }; + 1A00309B1FC3043900E02B93 /* rapidGVF */ = { + isa = PBXGroup; + children = ( + 1A00309C1FC3043900E02B93 /* rapidGVF.cpp */, + 1A00309D1FC3043900E02B93 /* rapidGVF.h */, + ); + path = rapidGVF; + sourceTree = "<group>"; + }; + 1A00309E1FC3043900E02B93 /* rapidXMM */ = { + isa = PBXGroup; + children = ( + 1A00309F1FC3043900E02B93 /* rapidXMM.cpp */, + 1A0030A01FC3043900E02B93 /* rapidXMM.h */, + ); + path = rapidXMM; + sourceTree = "<group>"; + }; + 1A0030A41FC3043900E02B93 /* signalProcessing */ = { + isa = PBXGroup; + children = ( + 1A0030A51FC3043900E02B93 /* rapidPiPoTools */, + 1A0030A91FC3043900E02B93 /* signalProcessing.h */, + ); + path = signalProcessing; + sourceTree = "<group>"; + }; + 1A0030A51FC3043900E02B93 /* rapidPiPoTools */ = { + isa = PBXGroup; + children = ( + 1A0030A61FC3043900E02B93 /* rapidPiPoHost.cpp */, + 1A0030A71FC3043900E02B93 /* rapidPiPoHost.h */, + 1A0030A81FC3043900E02B93 /* rapidPiPoTools.h */, + ); + path = rapidPiPoTools; + sourceTree = "<group>"; + }; + 1A73293F1FC30563001E730B /* dependencies */ = { + isa = PBXGroup; + children = ( + 1A7329401FC30563001E730B /* GVF */, + 1A732AFC1FC30563001E730B /* pipo */, + 1A732BAC1FC30563001E730B /* RapidLib */, + 1A732EC01FC30565001E730B /* third_party */, + 1A732ECC1FC30565001E730B /* xmm */, + ); + path = dependencies; + sourceTree = "<group>"; + }; + 1A7329401FC30563001E730B /* GVF */ = { + isa = PBXGroup; + children = ( + 1A7329411FC30563001E730B /* GVF.cpp */, + 1A7329421FC30563001E730B /* GVF.h */, + 1A7329431FC30563001E730B /* GVFGesture.h */, + 1A7329441FC30563001E730B /* GVFUtils.h */, + 1A7329451FC30563001E730B /* LICENSE */, + ); + path = GVF; + sourceTree = "<group>"; + }; + 1A732AFC1FC30563001E730B /* pipo */ = { + isa = PBXGroup; + children = ( + 1A732AFD1FC30563001E730B /* .gitignore */, + 1A732AFE1FC30563001E730B /* bin */, + 1A732B301FC30563001E730B /* README.md */, + 1A732B311FC30563001E730B /* src */, + ); + path = pipo; + sourceTree = "<group>"; + }; + 1A732AFE1FC30563001E730B /* bin */ = { + isa = PBXGroup; + children = ( + 1A732AFF1FC30563001E730B /* osx */, + ); + path = bin; + sourceTree = "<group>"; + }; + 1A732AFF1FC30563001E730B /* osx */ = { + isa = PBXGroup; + children = ( + 1A732B001FC30563001E730B /* libpipo.a */, + ); + path = osx; + sourceTree = "<group>"; + }; + 1A732B311FC30563001E730B /* src */ = { + isa = PBXGroup; + children = ( + 1A732B321FC30563001E730B /* dependencies */, + 1A732B761FC30563001E730B /* host */, + 1A732B7D1FC30563001E730B /* include */, + 1A732B831FC30563001E730B /* modules */, + ); + path = src; + sourceTree = "<group>"; + }; + 1A732B321FC30563001E730B /* dependencies */ = { + isa = PBXGroup; + children = ( + 1A732B331FC30563001E730B /* bayesfilter */, + 1A732B381FC30563001E730B /* finitedifferences */, + 1A732B3B1FC30563001E730B /* lpcformants */, + 1A732B401FC30563001E730B /* rta */, + ); + path = dependencies; + sourceTree = "<group>"; + }; + 1A732B331FC30563001E730B /* bayesfilter */ = { + isa = PBXGroup; + children = ( + 1A732B341FC30563001E730B /* BayesianFilter.cpp */, + 1A732B351FC30563001E730B /* BayesianFilter.h */, + 1A732B361FC30563001E730B /* filter_utilities.cpp */, + 1A732B371FC30563001E730B /* filter_utilities.h */, + ); + path = bayesfilter; + sourceTree = "<group>"; + }; + 1A732B381FC30563001E730B /* finitedifferences */ = { + isa = PBXGroup; + children = ( + 1A732B391FC30563001E730B /* finitedifferences.c */, + 1A732B3A1FC30563001E730B /* finitedifferences.h */, + ); + path = finitedifferences; + sourceTree = "<group>"; + }; + 1A732B3B1FC30563001E730B /* lpcformants */ = { + isa = PBXGroup; + children = ( + 1A732B3C1FC30563001E730B /* bbpr.cpp */, + 1A732B3D1FC30563001E730B /* bbpr.h */, + 1A732B3E1FC30563001E730B /* rpoly.cpp */, + 1A732B3F1FC30563001E730B /* rpoly.h */, + ); + path = lpcformants; + sourceTree = "<group>"; + }; + 1A732B401FC30563001E730B /* rta */ = { + isa = PBXGroup; + children = ( + 1A732B411FC30563001E730B /* common */, + 1A732B4F1FC30563001E730B /* misc */, + 1A732B751FC30563001E730B /* rta_configuration.h */, + ); + path = rta; + sourceTree = "<group>"; + }; + 1A732B411FC30563001E730B /* common */ = { + isa = PBXGroup; + children = ( + 1A732B421FC30563001E730B /* rta.h */, + 1A732B431FC30563001E730B /* rta_bpf.c */, + 1A732B441FC30563001E730B /* rta_bpf.h */, + 1A732B451FC30563001E730B /* rta_complex.h */, + 1A732B461FC30563001E730B /* rta_float.h */, + 1A732B471FC30563001E730B /* rta_int.c */, + 1A732B481FC30563001E730B /* rta_int.h */, + 1A732B491FC30563001E730B /* rta_math.h */, + 1A732B4A1FC30563001E730B /* rta_stdio.h */, + 1A732B4B1FC30563001E730B /* rta_stdlib.h */, + 1A732B4C1FC30563001E730B /* rta_types.h */, + 1A732B4D1FC30563001E730B /* rta_util.c */, + 1A732B4E1FC30563001E730B /* rta_util.h */, + ); + path = common; + sourceTree = "<group>"; + }; + 1A732B4F1FC30563001E730B /* misc */ = { + isa = PBXGroup; + children = ( + 1A732B501FC30563001E730B /* rta_bands.c */, + 1A732B511FC30563001E730B /* rta_bands.h */, + 1A732B521FC30563001E730B /* rta_biquad.c */, + 1A732B531FC30563001E730B /* rta_biquad.h */, + 1A732B541FC30563001E730B /* rta_correlation.c */, + 1A732B551FC30563001E730B /* rta_correlation.h */, + 1A732B561FC30563001E730B /* rta_cubic.c */, + 1A732B571FC30563001E730B /* rta_cubic.h */, + 1A732B581FC30563001E730B /* rta_dct.c */, + 1A732B591FC30563001E730B /* rta_dct.h */, + 1A732B5A1FC30563001E730B /* rta_delta.c */, + 1A732B5B1FC30563001E730B /* rta_delta.h */, + 1A732B5C1FC30563001E730B /* rta_fft.c */, + 1A732B5D1FC30563001E730B /* rta_fft.h */, + 1A732B5E1FC30563001E730B /* rta_filter.h */, + 1A732B5F1FC30563001E730B /* rta_lifter.c */, + 1A732B601FC30563001E730B /* rta_lifter.h */, + 1A732B611FC30563001E730B /* rta_lpc.c */, + 1A732B621FC30563001E730B /* rta_lpc.h */, + 1A732B631FC30563001E730B /* rta_mean_variance.c */, + 1A732B641FC30563001E730B /* rta_mean_variance.h */, + 1A732B651FC30563001E730B /* rta_mel.c */, + 1A732B661FC30563001E730B /* rta_mel.h */, + 1A732B671FC30563001E730B /* rta_moments.c */, + 1A732B681FC30563001E730B /* rta_moments.h */, + 1A732B691FC30563001E730B /* rta_onepole.c */, + 1A732B6A1FC30563001E730B /* rta_onepole.h */, + 1A732B6B1FC30563001E730B /* rta_preemphasis.c */, + 1A732B6C1FC30563001E730B /* rta_preemphasis.h */, + 1A732B6D1FC30563001E730B /* rta_resample.c */, + 1A732B6E1FC30563001E730B /* rta_resample.h */, + 1A732B6F1FC30563001E730B /* rta_selection.c */, + 1A732B701FC30563001E730B /* rta_selection.h */, + 1A732B711FC30563001E730B /* rta_svd.c */, + 1A732B721FC30563001E730B /* rta_svd.h */, + 1A732B731FC30563001E730B /* rta_window.c */, + 1A732B741FC30563001E730B /* rta_window.h */, + ); + path = misc; + sourceTree = "<group>"; + }; + 1A732B761FC30563001E730B /* host */ = { + isa = PBXGroup; + children = ( + 1A732B771FC30563001E730B /* mimo_host.h */, + 1A732B781FC30563001E730B /* PiPoCollection.cpp */, + 1A732B791FC30563001E730B /* PiPoCollection.h */, + 1A732B7A1FC30563001E730B /* PiPoGraph.h */, + 1A732B7B1FC30563001E730B /* PiPoHost.h */, + 1A732B7C1FC30563001E730B /* PiPoModule.h */, + ); + path = host; + sourceTree = "<group>"; + }; + 1A732B7D1FC30563001E730B /* include */ = { + isa = PBXGroup; + children = ( + 1A732B7E1FC30563001E730B /* mimo.h */, + 1A732B7F1FC30563001E730B /* PiPo.h */, + 1A732B801FC30563001E730B /* PiPoParallel.h */, + 1A732B811FC30563001E730B /* PiPoSequence.h */, + 1A732B821FC30563001E730B /* RingBuffer.h */, + ); + path = include; + sourceTree = "<group>"; + }; + 1A732B831FC30563001E730B /* modules */ = { + isa = PBXGroup; + children = ( + 1A732B841FC30563001E730B /* mimo */, + 1A732B861FC30563001E730B /* PiPoBands.h */, + 1A732B871FC30563001E730B /* PiPoBayesFilter.h */, + 1A732B881FC30563001E730B /* PiPoBiquad.h */, + 1A732B891FC30563001E730B /* PiPoChop.h */, + 1A732B8A1FC30563001E730B /* PiPoConst.h */, + 1A732B8B1FC30563001E730B /* PiPoDct.h */, + 1A732B8C1FC30563001E730B /* PiPoDelta.h */, + 1A732B8D1FC30563001E730B /* PiPoFft.h */, + 1A732B8E1FC30563001E730B /* PiPoFiniteDif.h */, + 1A732B8F1FC30563001E730B /* PiPoGate.h */, + 1A732B901FC30563001E730B /* PiPoLpc.h */, + 1A732B911FC30563001E730B /* PiPoLpcFormants.h */, + 1A732B921FC30563001E730B /* PiPoMeanStddev.h */, + 1A732B931FC30563001E730B /* PiPoMedian.h */, + 1A732B941FC30563001E730B /* PiPoMel.h */, + 1A732B951FC30563001E730B /* PiPoMfcc.h */, + 1A732B961FC30563001E730B /* PiPoMinMax.h */, + 1A732B971FC30563001E730B /* PiPoMoments.h */, + 1A732B981FC30563001E730B /* PiPoMvavrg.h */, + 1A732B991FC30563001E730B /* PiPoOnseg.h */, + 1A732B9A1FC30563001E730B /* PiPoPeaks.h */, + 1A732B9B1FC30563001E730B /* PiPoRms.h */, + 1A732B9C1FC30563001E730B /* PiPoScale.h */, + 1A732B9D1FC30563001E730B /* PiPoSelect.h */, + 1A732B9E1FC30563001E730B /* PiPoSlice.h */, + 1A732B9F1FC30563001E730B /* PiPoSum.h */, + 1A732BA01FC30563001E730B /* TempMod.h */, + ); + path = modules; + sourceTree = "<group>"; + }; + 1A732B841FC30563001E730B /* mimo */ = { + isa = PBXGroup; + children = ( + 1A732B851FC30563001E730B /* mimo_stats.h */, + ); + path = mimo; + sourceTree = "<group>"; + }; + 1A732BAC1FC30563001E730B /* RapidLib */ = { + isa = PBXGroup; + children = ( + 1A732BAF1FC30563001E730B /* dependencies */, + 1A732E861FC30565001E730B /* src */, + ); + path = RapidLib; + sourceTree = "<group>"; + }; + 1A732BAF1FC30563001E730B /* dependencies */ = { + isa = PBXGroup; + children = ( + 1A732BB01FC30563001E730B /* json */, + 1A732BB31FC30563001E730B /* jsoncpp.cpp */, + 1A732BB41FC30563001E730B /* libsvm */, + ); + path = dependencies; + sourceTree = "<group>"; + }; + 1A732BB01FC30563001E730B /* json */ = { + isa = PBXGroup; + children = ( + 1A732BB11FC30563001E730B /* json-forwards.h */, + 1A732BB21FC30563001E730B /* json.h */, + ); + path = json; + sourceTree = "<group>"; + }; + 1A732BB41FC30563001E730B /* libsvm */ = { + isa = PBXGroup; + children = ( + 1A732BB51FC30563001E730B /* libsvm.cpp */, + 1A732BB61FC30563001E730B /* libsvm.h */, + ); + path = libsvm; + sourceTree = "<group>"; + }; + 1A732E861FC30565001E730B /* src */ = { + isa = PBXGroup; + children = ( + 1A732E871FC30565001E730B /* baseModel.h */, + 1A732E881FC30565001E730B /* classification.cpp */, + 1A732E891FC30565001E730B /* classification.h */, + 1A732E8A1FC30565001E730B /* dtw.cpp */, + 1A732E8B1FC30565001E730B /* dtw.h */, + 1A732E8C1FC30565001E730B /* emscripten */, + 1A732E971FC30565001E730B /* fastDTW.cpp */, + 1A732E981FC30565001E730B /* fastDTW.h */, + 1A732E991FC30565001E730B /* knnClassification.cpp */, + 1A732E9A1FC30565001E730B /* knnClassification.h */, + 1A732E9B1FC30565001E730B /* modelSet.cpp */, + 1A732E9C1FC30565001E730B /* modelSet.h */, + 1A732E9D1FC30565001E730B /* neuralNetwork.cpp */, + 1A732E9E1FC30565001E730B /* neuralNetwork.h */, + 1A732E9F1FC30565001E730B /* rapidStream.cpp */, + 1A732EA01FC30565001E730B /* rapidStream.h */, + 1A732EA11FC30565001E730B /* regression.cpp */, + 1A732EA21FC30565001E730B /* regression.h */, + 1A732EA31FC30565001E730B /* searchWindow.cpp */, + 1A732EA41FC30565001E730B /* searchWindow.h */, + 1A732EA51FC30565001E730B /* seriesClassification.cpp */, + 1A732EA61FC30565001E730B /* seriesClassification.h */, + 1A732EA71FC30565001E730B /* svmClassification.cpp */, + 1A732EA81FC30565001E730B /* svmClassification.h */, + 1A732EA91FC30565001E730B /* trainingExample.h */, + 1A732EAA1FC30565001E730B /* warpPath.cpp */, + 1A732EAB1FC30565001E730B /* warpPath.h */, + ); + path = src; + sourceTree = "<group>"; + }; + 1A732E8C1FC30565001E730B /* emscripten */ = { + isa = PBXGroup; + children = ( + 1A732E8D1FC30565001E730B /* classificationEmbindings.h */, + 1A732E8E1FC30565001E730B /* knnEmbindings.h */, + 1A732E8F1FC30565001E730B /* modelSetEmbindings.h */, + 1A732E901FC30565001E730B /* nnEmbindings.h */, + 1A732E911FC30565001E730B /* nodeEnv.js */, + 1A732E921FC30565001E730B /* rapidLibPost.js */, + 1A732E931FC30565001E730B /* rapidStreamEmbindings.h */, + 1A732E941FC30565001E730B /* regressionEmbindings.h */, + 1A732E951FC30565001E730B /* seriesClassificationEmbindings.h */, + 1A732E961FC30565001E730B /* svmEmbindings.h */, + ); + path = emscripten; + sourceTree = "<group>"; + }; + 1A732EC01FC30565001E730B /* third_party */ = { + isa = PBXGroup; + children = ( + 1A732EC11FC30565001E730B /* catch */, + 1A732EC41FC30565001E730B /* json */, + 1A732EC71FC30565001E730B /* jsoncpp.cpp */, + 1A732EC81FC30565001E730B /* libsvm */, + ); + path = third_party; + sourceTree = "<group>"; + }; + 1A732EC11FC30565001E730B /* catch */ = { + isa = PBXGroup; + children = ( + 1A732EC21FC30565001E730B /* catch.hpp */, + 1A732EC31FC30565001E730B /* LICENSE_1_0.txt */, + ); + path = catch; + sourceTree = "<group>"; + }; + 1A732EC41FC30565001E730B /* json */ = { + isa = PBXGroup; + children = ( + 1A732EC51FC30565001E730B /* json-forwards.h */, + 1A732EC61FC30565001E730B /* json.h */, + ); + path = json; + sourceTree = "<group>"; + }; + 1A732EC81FC30565001E730B /* libsvm */ = { + isa = PBXGroup; + children = ( + 1A732EC91FC30565001E730B /* libsvm.cpp */, + 1A732ECA1FC30565001E730B /* libsvm.h */, + 1A732ECB1FC30565001E730B /* LICENSE */, + ); + path = libsvm; + sourceTree = "<group>"; + }; + 1A732ECC1FC30565001E730B /* xmm */ = { + isa = PBXGroup; + children = ( + 1A732ECD1FC30565001E730B /* .gitignore */, + 1A732ECE1FC30565001E730B /* CMakeLists.txt */, + 1A732ECF1FC30565001E730B /* dependencies */, + 1A732EE51FC30565001E730B /* doc */, + 1A732EF91FC30565001E730B /* LICENSE */, + 1A732F121FC30565001E730B /* readme.md */, + 1A732F131FC30565001E730B /* src */, + ); + path = xmm; + sourceTree = "<group>"; + }; + 1A732ECF1FC30565001E730B /* dependencies */ = { + isa = PBXGroup; + children = ( + 1A732ED01FC30565001E730B /* catch */, + 1A732ED21FC30565001E730B /* jsoncpp */, + ); + path = dependencies; + sourceTree = "<group>"; + }; + 1A732ED01FC30565001E730B /* catch */ = { + isa = PBXGroup; + children = ( + 1A732ED11FC30565001E730B /* catch.hpp */, + ); + path = catch; + sourceTree = "<group>"; + }; + 1A732ED21FC30565001E730B /* jsoncpp */ = { + isa = PBXGroup; + children = ( + 1A732ED31FC30565001E730B /* include */, + 1A732EDE1FC30565001E730B /* LICENSE */, + 1A732EDF1FC30565001E730B /* src */, + ); + path = jsoncpp; + sourceTree = "<group>"; + }; + 1A732ED31FC30565001E730B /* include */ = { + isa = PBXGroup; + children = ( + 1A732ED41FC30565001E730B /* assertions.h */, + 1A732ED51FC30565001E730B /* autolink.h */, + 1A732ED61FC30565001E730B /* config.h */, + 1A732ED71FC30565001E730B /* forwards.h */, + 1A732ED81FC30565001E730B /* json-features.h */, + 1A732ED91FC30565001E730B /* json.h */, + 1A732EDA1FC30565001E730B /* reader.h */, + 1A732EDB1FC30565001E730B /* value.h */, + 1A732EDC1FC30565001E730B /* version.h */, + 1A732EDD1FC30565001E730B /* writer.h */, + ); + path = include; + sourceTree = "<group>"; + }; + 1A732EDF1FC30565001E730B /* src */ = { + isa = PBXGroup; + children = ( + 1A732EE01FC30565001E730B /* json_reader.cpp */, + 1A732EE11FC30565001E730B /* json_tool.h */, + 1A732EE21FC30565001E730B /* json_value.cpp */, + 1A732EE31FC30565001E730B /* json_valueiterator.inl */, + 1A732EE41FC30565001E730B /* json_writer.cpp */, + ); + path = src; + sourceTree = "<group>"; + }; + 1A732EE51FC30565001E730B /* doc */ = { + isa = PBXGroup; + children = ( + 1A732EE61FC30565001E730B /* doc-misc */, + 1A732EF21FC30565001E730B /* Doxyfile */, + 1A732EF31FC30565001E730B /* Doxyfile-dot */, + ); + path = doc; + sourceTree = "<group>"; + }; + 1A732EE61FC30565001E730B /* doc-misc */ = { + isa = PBXGroup; + children = ( + 1A732EE71FC30565001E730B /* footer.html */, + 1A732EE81FC30565001E730B /* header.html */, + 1A732EE91FC30565001E730B /* jdoxygen.css */, + 1A732EEA1FC30565001E730B /* jtabs.css */, + 1A732EEB1FC30565001E730B /* python_example.py */, + 1A732EEC1FC30565001E730B /* QuickStart_Python.html */, + 1A732EED1FC30565001E730B /* xmm_architecture.jpg */, + 1A732EEE1FC30565001E730B /* xmm_featured.jpg */, + 1A732EEF1FC30565001E730B /* xmm_featured_.jpg */, + 1A732EF01FC30565001E730B /* xmm_models.jpg */, + 1A732EF11FC30565001E730B /* XmmDoxygenLayout.xml */, + ); + path = "doc-misc"; + sourceTree = "<group>"; + }; + 1A732F131FC30565001E730B /* src */ = { + isa = PBXGroup; + children = ( + 1A732F141FC30565001E730B /* core */, + 1A732F2E1FC30565001E730B /* models */, + 1A732F441FC30565001E730B /* xmm.h */, + ); + path = src; + sourceTree = "<group>"; + }; + 1A732F141FC30565001E730B /* core */ = { + isa = PBXGroup; + children = ( + 1A732F151FC30565001E730B /* common */, + 1A732F1D1FC30565001E730B /* distributions */, + 1A732F201FC30565001E730B /* model */, + 1A732F291FC30565001E730B /* trainingset */, + ); + path = core; + sourceTree = "<group>"; + }; + 1A732F151FC30565001E730B /* common */ = { + isa = PBXGroup; + children = ( + 1A732F161FC30565001E730B /* xmmAttribute.cpp */, + 1A732F171FC30565001E730B /* xmmAttribute.hpp */, + 1A732F181FC30565001E730B /* xmmCircularbuffer.hpp */, + 1A732F191FC30565001E730B /* xmmEvents.hpp */, + 1A732F1A1FC30565001E730B /* xmmJson.cpp */, + 1A732F1B1FC30565001E730B /* xmmJson.hpp */, + 1A732F1C1FC30565001E730B /* xmmMatrix.hpp */, + ); + path = common; + sourceTree = "<group>"; + }; + 1A732F1D1FC30565001E730B /* distributions */ = { + isa = PBXGroup; + children = ( + 1A732F1E1FC30565001E730B /* xmmGaussianDistribution.cpp */, + 1A732F1F1FC30565001E730B /* xmmGaussianDistribution.hpp */, + ); + path = distributions; + sourceTree = "<group>"; + }; + 1A732F201FC30565001E730B /* model */ = { + isa = PBXGroup; + children = ( + 1A732F211FC30565001E730B /* xmmModel.hpp */, + 1A732F221FC30565001E730B /* xmmModelConfiguration.hpp */, + 1A732F231FC30565001E730B /* xmmModelParameters.hpp */, + 1A732F241FC30565001E730B /* xmmModelResults.hpp */, + 1A732F251FC30565001E730B /* xmmModelSharedParameters.cpp */, + 1A732F261FC30565001E730B /* xmmModelSharedParameters.hpp */, + 1A732F271FC30565001E730B /* xmmModelSingleClass.cpp */, + 1A732F281FC30565001E730B /* xmmModelSingleClass.hpp */, + ); + path = model; + sourceTree = "<group>"; + }; + 1A732F291FC30565001E730B /* trainingset */ = { + isa = PBXGroup; + children = ( + 1A732F2A1FC30565001E730B /* xmmPhrase.cpp */, + 1A732F2B1FC30565001E730B /* xmmPhrase.hpp */, + 1A732F2C1FC30565001E730B /* xmmTrainingSet.cpp */, + 1A732F2D1FC30565001E730B /* xmmTrainingSet.hpp */, + ); + path = trainingset; + sourceTree = "<group>"; + }; + 1A732F2E1FC30565001E730B /* models */ = { + isa = PBXGroup; + children = ( + 1A732F2F1FC30565001E730B /* gmm */, + 1A732F361FC30565001E730B /* hmm */, + 1A732F3E1FC30565001E730B /* kmeans */, + ); + path = models; + sourceTree = "<group>"; + }; + 1A732F2F1FC30565001E730B /* gmm */ = { + isa = PBXGroup; + children = ( + 1A732F301FC30565001E730B /* xmmGmm.cpp */, + 1A732F311FC30565001E730B /* xmmGmm.hpp */, + 1A732F321FC30565001E730B /* xmmGmmParameters.cpp */, + 1A732F331FC30565001E730B /* xmmGmmParameters.hpp */, + 1A732F341FC30565001E730B /* xmmGmmSingleClass.cpp */, + 1A732F351FC30565001E730B /* xmmGmmSingleClass.hpp */, + ); + path = gmm; + sourceTree = "<group>"; + }; + 1A732F361FC30565001E730B /* hmm */ = { + isa = PBXGroup; + children = ( + 1A732F371FC30565001E730B /* xmmHierarchicalHmm.cpp */, + 1A732F381FC30565001E730B /* xmmHierarchicalHmm.hpp */, + 1A732F391FC30565001E730B /* xmmHmmParameters.cpp */, + 1A732F3A1FC30565001E730B /* xmmHmmParameters.hpp */, + 1A732F3B1FC30565001E730B /* xmmHmmResults.hpp */, + 1A732F3C1FC30565001E730B /* xmmHmmSingleClass.cpp */, + 1A732F3D1FC30565001E730B /* xmmHmmSingleClass.hpp */, + ); + path = hmm; + sourceTree = "<group>"; + }; + 1A732F3E1FC30565001E730B /* kmeans */ = { + isa = PBXGroup; + children = ( + 1A732F3F1FC30565001E730B /* xmmKMeans.cpp */, + 1A732F401FC30565001E730B /* xmmKMeans.hpp */, + 1A732F411FC30565001E730B /* xmmKMeansParameters.cpp */, + 1A732F421FC30565001E730B /* xmmKMeansParameters.hpp */, + 1A732F431FC30565001E730B /* xmmKMeansResults.hpp */, + ); + path = kmeans; + sourceTree = "<group>"; + }; + 1AF8F4F51FBFBA68007845B3 /* Bitalino */ = { + isa = PBXGroup; + children = ( + 1AF8F4F31FBFBA56007845B3 /* bitalino.h */, + 1AF8F4F21FBFBA56007845B3 /* bitalino.cpp */, + 1AF8F4FF1FC106D2007845B3 /* ThreadedProcess.h */, + 1AF8F5001FC108DE007845B3 /* BitalinoThread.h */, + 1AFD55011FC1C73500BDC5EC /* RapidMixThread.h */, + 1AF8F4FD1FC0D5C6007845B3 /* RingBuffer.hpp */, + 1A04D8C21FC31C0000D725DC /* RapidBitalino.h */, + 1A04D8C31FC31D0E00D725DC /* RapidBitalino.cpp */, + ); + name = Bitalino; + sourceTree = "<group>"; + }; + 30CB364908817057B430D528 /* osc */ = { + isa = PBXGroup; + children = ( + F0448463C9530F4935705C48 /* MessageMappingOscPacketListener.h */, + D6A1246E09C6B8CDA06EEC4F /* OscException.h */, + 7FDED04B5307798C8725EDDE /* OscHostEndianness.h */, + 16F2E6A76B43CC86E0875826 /* OscOutboundPacketStream.cpp */, + 771343C29ADB1A34A5E3F2D7 /* OscOutboundPacketStream.h */, + 7805756184CF7E3670EBA6B9 /* OscPacketListener.h */, + 6EFE170390703388444A995C /* OscPrintReceivedElements.cpp */, + AA63660625DF3459DBD8486C /* OscPrintReceivedElements.h */, + 333B161A45E42EF09ADEC7A5 /* OscReceivedElements.cpp */, + 6107D0B5FEEE887645CC8673 /* OscReceivedElements.h */, + E87C4F253FACA6BBF714AD99 /* OscTypes.cpp */, + 47DFCF539679C49445A74E64 /* OscTypes.h */, + ); + name = osc; + sourceTree = "<group>"; + }; + 38871A5825686AE018EC2BF0 /* libs */ = { + isa = PBXGroup; + children = ( + 86D2677079A3AF4A5A88E29A /* oscpack */, + ); + name = libs; + sourceTree = "<group>"; + }; + 480A780D8D0308AE4A368801 /* ofxGui */ = { + isa = PBXGroup; + children = ( + A763ED608B35AE3310251DEE /* src */, + ); + name = ofxGui; + sourceTree = "<group>"; + }; + 4ACC32F17B7623DA048865D1 /* libs */ = { + isa = PBXGroup; + children = ( + DC8DE4E32DB58B5849214F05 /* fft.cpp */, + 43AF2D57607DD0B4AF3A6183 /* fft.h */, + 21080C6D8829F198543F568E /* maxiAtoms.cpp */, + EB00468633B458B3AF898FAC /* maxiAtoms.h */, + E79D78A192005C0D7FDA98C0 /* maxiBark.cpp */, + 50B91A7EB2184FD67A06D044 /* maxiBark.h */, + 6D7D4C890B7E7E86CF67EDE9 /* maxiFFT.cpp */, + 3B129EA9D541BE47A473BC06 /* maxiFFT.h */, + 300B4DCCFFECBD546568227A /* maxiGrains.cpp */, + E808847ECDCE62ABFF8D5E4D /* maxiGrains.h */, + C590EAED7C04204257DE2745 /* maxiMFCC.cpp */, + FC08FD52F6639D7D5EC893D6 /* maxiMFCC.h */, + 0FEC22E5BFC33148A93E906A /* maximilian.cpp */, + 008629CF1C50CAC655956424 /* maximilian.h */, + 3F1F7648BBA70B28FE923560 /* sineTable.h */, + 8DC5D79A78655BF028FBDE30 /* stb_vorbis.c */, + 57C2E0F28BA237CECA2DD2F3 /* stb_vorbis.h */, + ); + name = libs; + sourceTree = "<group>"; + }; + 6234D3BCE87D1C3BA2230F19 /* ofxMaxim */ = { + isa = PBXGroup; + children = ( + 8F6BFB59AB6D0A458C2F3C53 /* src */, + 4ACC32F17B7623DA048865D1 /* libs */, + ); + name = ofxMaxim; + sourceTree = "<group>"; + }; + 641362CA659FAFEE4E81001B /* posix */ = { + isa = PBXGroup; + children = ( + 54C5AF569662A8351667313E /* NetworkingUtils.cpp */, + 138DE2396984C9C63DA7FDD6 /* UdpSocket.cpp */, + ); + name = posix; + sourceTree = "<group>"; + }; + 6948EE371B920CB800B5AC1A /* local_addons */ = { + isa = PBXGroup; + children = ( + ); + name = local_addons; + sourceTree = "<group>"; + }; + 86D2677079A3AF4A5A88E29A /* oscpack */ = { + isa = PBXGroup; + children = ( + D27B2221A225CA523C019676 /* src */, + ); + name = oscpack; + sourceTree = "<group>"; + }; + 8F6BFB59AB6D0A458C2F3C53 /* src */ = { + isa = PBXGroup; + children = ( + A93736CA5EE7029E798A22AA /* ofxMaxim.h */, + ); + name = src; + sourceTree = "<group>"; + }; + A763ED608B35AE3310251DEE /* src */ = { + isa = PBXGroup; + children = ( + 283D3449127FCD4AE5F47F88 /* ofxBaseGui.cpp */, + 3A6FBE64E557C85D306947E4 /* ofxBaseGui.h */, + E76982C6091099847AF4A689 /* ofxButton.cpp */, + 4A2FCA86040F43BCB2C12BCA /* ofxButton.h */, + D9460E080AF572AB4FE572C2 /* ofxGui.h */, + 161030033DD4104A32E68FA8 /* ofxGuiGroup.cpp */, + F4750E6716D760CCBF1143CF /* ofxGuiGroup.h */, + C85AEC4A09E7407508E41723 /* ofxLabel.cpp */, + 4169271F18AE49EFC953B0AB /* ofxLabel.h */, + 3646FFD002EE9FED0DD367F3 /* ofxPanel.cpp */, + 86ECBAD17F7B1D927CB1931F /* ofxPanel.h */, + 951C54CCCD72A0FFC773653F /* ofxSlider.cpp */, + F890C575BD59092852BD3CB2 /* ofxSlider.h */, + E661ACAA5BEC5B96FD2F6532 /* ofxSliderGroup.cpp */, + B86B7BDD7ADBAB228DB14744 /* ofxSliderGroup.h */, + 5BA6903E0287C0B3CBF81989 /* ofxToggle.cpp */, + C00AD5B8094B3634B06C5926 /* ofxToggle.h */, + ); + name = src; + sourceTree = "<group>"; + }; + BB4B014C10F69532006C3DED /* addons */ = { + isa = PBXGroup; + children = ( + 480A780D8D0308AE4A368801 /* ofxGui */, + 6234D3BCE87D1C3BA2230F19 /* ofxMaxim */, + E6053AB7FEC63D5F83825B88 /* ofxOsc */, + ); + name = addons; + sourceTree = "<group>"; + }; + BD2F1A9F8D0C05EDB29122D0 /* src */ = { + isa = PBXGroup; + children = ( + 33C51958AA0CAE4F88D953DC /* ofxOsc.h */, + DE6FBA724BBE5D9249AC3BCF /* ofxOscArg.h */, + 1661CDE0EE45AC19EF11DA8E /* ofxOscBundle.cpp */, + 6D68865B98C85481FB07D746 /* ofxOscBundle.h */, + D39514497AFC9A4AAE903696 /* ofxOscMessage.cpp */, + F0DBD3DF50BD6761963D69B6 /* ofxOscMessage.h */, + DCB987CA7BF7FB3A39EF3514 /* ofxOscParameterSync.cpp */, + 5D3DC557A3FD0ADFC8D06276 /* ofxOscParameterSync.h */, + 8F5FFC9C08A87AE48EA5E66C /* ofxOscReceiver.cpp */, + 0D0D8D193987B4296465A319 /* ofxOscReceiver.h */, + AEC6D21EB03AE1B72B35D0D9 /* ofxOscSender.cpp */, + FCCD68796F8A249EA9FEDD44 /* ofxOscSender.h */, + ); + name = src; + sourceTree = "<group>"; + }; + D27B2221A225CA523C019676 /* src */ = { + isa = PBXGroup; + children = ( + FF8CDF57858E9B94E3237115 /* ip */, + 30CB364908817057B430D528 /* osc */, + ); + name = src; + sourceTree = "<group>"; + }; + E4328144138ABC890047C5CB /* Products */ = { + isa = PBXGroup; + children = ( + E4328148138ABC890047C5CB /* openFrameworksDebug.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + E4B69B4A0A3A1720003C02F2 = { + isa = PBXGroup; + children = ( + E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */, + E4EB6923138AFD0F00A09F29 /* Project.xcconfig */, + 1A04D8D71FC38F3700D725DC /* libRAPID-MIX_API.a */, + 1A002A861FC303F700E02B93 /* Rapid-Mix */, + E4B69E1C0A3A1BDC003C02F2 /* src */, + E4EEC9E9138DF44700A80321 /* openFrameworks */, + BB4B014C10F69532006C3DED /* addons */, + 6948EE371B920CB800B5AC1A /* local_addons */, + E4B69B5B0A3A1756003C02F2 /* BitalinoDebug.app */, + ); + sourceTree = "<group>"; + }; + E4B69E1C0A3A1BDC003C02F2 /* src */ = { + isa = PBXGroup; + children = ( + 1AF8F4F51FBFBA68007845B3 /* Bitalino */, + E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */, + E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */, + E4B69E1D0A3A1BDC003C02F2 /* main.cpp */, + ); + path = src; + sourceTree = SOURCE_ROOT; + }; + E4EEC9E9138DF44700A80321 /* openFrameworks */ = { + isa = PBXGroup; + children = ( + E4EB691F138AFCF100A09F29 /* CoreOF.xcconfig */, + E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */, + ); + name = openFrameworks; + sourceTree = "<group>"; + }; + E6053AB7FEC63D5F83825B88 /* ofxOsc */ = { + isa = PBXGroup; + children = ( + BD2F1A9F8D0C05EDB29122D0 /* src */, + 38871A5825686AE018EC2BF0 /* libs */, + ); + name = ofxOsc; + sourceTree = "<group>"; + }; + FF8CDF57858E9B94E3237115 /* ip */ = { + isa = PBXGroup; + children = ( + 552D90E7024A93518E711979 /* IpEndpointName.cpp */, + 2E39787D52B2DB29CF1FCF66 /* IpEndpointName.h */, + 5065E0436E391619A021DE76 /* NetworkingUtils.h */, + 09AEC4E5ECE805EAD349DBCE /* PacketListener.h */, + 641362CA659FAFEE4E81001B /* posix */, + 0972B751F7A633CC3CCD4C70 /* TimerListener.h */, + DD3E35208D66CC444D100690 /* UdpSocket.h */, + ); + name = ip; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E4B69B5A0A3A1756003C02F2 /* Bitalino */ = { + isa = PBXNativeTarget; + buildConfigurationList = E4B69B5F0A3A1757003C02F2 /* Build configuration list for PBXNativeTarget "Bitalino" */; + buildPhases = ( + E4B69B580A3A1756003C02F2 /* Sources */, + E4B69B590A3A1756003C02F2 /* Frameworks */, + E4B6FFFD0C3F9AB9008CF71C /* ShellScript */, + E4C2427710CC5ABF004149E2 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + E4EEB9AC138B136A00A80321 /* PBXTargetDependency */, + ); + name = Bitalino; + productName = myOFApp; + productReference = E4B69B5B0A3A1756003C02F2 /* BitalinoDebug.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E4B69B4C0A3A1720003C02F2 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + }; + buildConfigurationList = E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "Bitalino" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = E4B69B4A0A3A1720003C02F2; + productRefGroup = E4B69B4A0A3A1720003C02F2; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = E4328144138ABC890047C5CB /* Products */; + ProjectRef = E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + E4B69B5A0A3A1756003C02F2 /* Bitalino */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + E4328148138ABC890047C5CB /* openFrameworksDebug.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = openFrameworksDebug.a; + remoteRef = E4328147138ABC890047C5CB /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXShellScriptBuildPhase section */ + E4B6FFFD0C3F9AB9008CF71C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/\"\n# Copy default icon file into App/Resources\nrsync -aved \"$ICON_FILE\" \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/\"\n# Copy libfmod and change install directory for fmod to run\nrsync -aved ../../../../../Documents/of_v0.9.8_osx_release/libs/fmodex/lib/osx/libfmodex.dylib \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/\";\ninstall_name_tool -change @executable_path/libfmodex.dylib @executable_path/../Frameworks/libfmodex.dylib \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME\";\n# Copy GLUT framework (must remove for AppStore submissions)\nrsync -aved ../../../../../Documents/of_v0.9.8_osx_release/libs/glut/lib/osx/GLUT.framework \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E4B69B580A3A1756003C02F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */, + 1A732FE01FC30566001E730B /* rta_lpc.c in Sources */, + 1A7330231FC30566001E730B /* xmmGmm.cpp in Sources */, + E4B69E210A3A1BDC003C02F2 /* ofApp.cpp in Sources */, + E6E8C6BA7D5DD18D84DCE6B9 /* ofxBaseGui.cpp in Sources */, + 1A732FE71FC30566001E730B /* rta_selection.c in Sources */, + 1F4CACB1B7D09B43508A7EC3 /* ofxButton.cpp in Sources */, + 1A732FF41FC30566001E730B /* libsvm.cpp in Sources */, + 1A73302A1FC30566001E730B /* xmmKMeansParameters.cpp in Sources */, + 9B232A695C4183B7E9D6DE6B /* ofxGuiGroup.cpp in Sources */, + 1A732FD11FC30566001E730B /* filter_utilities.cpp in Sources */, + 9DB59557693F5AF1C3B86978 /* ofxLabel.cpp in Sources */, + A6B3D68D6CAF91615E79B729 /* ofxPanel.cpp in Sources */, + 1A7330251FC30566001E730B /* xmmGmmSingleClass.cpp in Sources */, + 1A732FDB1FC30566001E730B /* rta_cubic.c in Sources */, + 1A7329241FC304D0001E730B /* rapidGVF.cpp in Sources */, + 1A732FDC1FC30566001E730B /* rta_dct.c in Sources */, + C1CCEDB5321AA5A832D215F0 /* ofxSlider.cpp in Sources */, + 0289606657F3E1B14D87F2BC /* ofxSliderGroup.cpp in Sources */, + 1A7329231FC304D0001E730B /* machineLearning.cpp in Sources */, + 1A732FE11FC30566001E730B /* rta_mean_variance.c in Sources */, + 1A73301F1FC30566001E730B /* xmmModelSharedParameters.cpp in Sources */, + 1AF8F4F41FBFBA56007845B3 /* bitalino.cpp in Sources */, + BE5879D980EF1A321B38BDED /* ofxToggle.cpp in Sources */, + CBF1E66610EC3ED02B8E7810 /* fft.cpp in Sources */, + 1A732FE81FC30566001E730B /* rta_svd.c in Sources */, + 1A732FD71FC30566001E730B /* rta_util.c in Sources */, + AE5D0283C3A439F21F24D146 /* maxiAtoms.cpp in Sources */, + 460809B55AD9FA35FEEF18E9 /* maxiBark.cpp in Sources */, + 821FDA0B1E4F7BB6AF683071 /* maxiFFT.cpp in Sources */, + 1A732FE61FC30566001E730B /* rta_resample.c in Sources */, + 10C531C84875D2C829391B4E /* maxiGrains.cpp in Sources */, + 1A7330071FC30566001E730B /* knnClassification.cpp in Sources */, + 982961365190FE97577EC25D /* maxiMFCC.cpp in Sources */, + 1A73300E1FC30566001E730B /* svmClassification.cpp in Sources */, + 77C1DBAB01757716D71545F7 /* maximilian.cpp in Sources */, + 1A732FDE1FC30566001E730B /* rta_fft.c in Sources */, + 1A732FD61FC30566001E730B /* rta_int.c in Sources */, + 1A732FE21FC30566001E730B /* rta_mel.c in Sources */, + 1A7330221FC30566001E730B /* xmmTrainingSet.cpp in Sources */, + 6DEA5ACAF78C6AE7BB6BFDCF /* stb_vorbis.c in Sources */, + 1A732FE51FC30566001E730B /* rta_preemphasis.c in Sources */, + 7BF363788124DFB219FEA2D9 /* ofxOscBundle.cpp in Sources */, + 1A732F4E1FC30565001E730B /* GVF.cpp in Sources */, + 83944CBA55088BC6E0CB8655 /* ofxOscMessage.cpp in Sources */, + 1A732FCF1FC30566001E730B /* README.md in Sources */, + 1A73300D1FC30566001E730B /* seriesClassification.cpp in Sources */, + 1A73300B1FC30566001E730B /* regression.cpp in Sources */, + 1A7330091FC30566001E730B /* neuralNetwork.cpp in Sources */, + 1A7330211FC30566001E730B /* xmmPhrase.cpp in Sources */, + 1A7330261FC30566001E730B /* xmmHierarchicalHmm.cpp in Sources */, + 1A7330061FC30566001E730B /* fastDTW.cpp in Sources */, + 1A7329261FC304D0001E730B /* trainingData.cpp in Sources */, + 1A7329251FC304D0001E730B /* rapidXMM.cpp in Sources */, + 1A732FE41FC30566001E730B /* rta_onepole.c in Sources */, + 1A73300F1FC30566001E730B /* warpPath.cpp in Sources */, + 1A732FDA1FC30566001E730B /* rta_correlation.c in Sources */, + C061F0FB55B94C461FF5D520 /* ofxOscParameterSync.cpp in Sources */, + 1A7330281FC30566001E730B /* xmmHmmSingleClass.cpp in Sources */, + 1A7330141FC30566001E730B /* jsoncpp.cpp in Sources */, + 617ACA40B63357D76A9595A8 /* ofxOscReceiver.cpp in Sources */, + C0A43D1F56B1198FC5EE7031 /* ofxOscSender.cpp in Sources */, + 1A732FD51FC30566001E730B /* rta_bpf.c in Sources */, + 1A73293D1FC304D5001E730B /* rapidPiPoHost.cpp in Sources */, + 1A732FDD1FC30566001E730B /* rta_delta.c in Sources */, + 06B42CCB73078EB0E8E265EE /* IpEndpointName.cpp in Sources */, + 1A7330081FC30566001E730B /* modelSet.cpp in Sources */, + 39B159E39B6636BFC65B0F2A /* NetworkingUtils.cpp in Sources */, + 230128348F328F3A83D41798 /* UdpSocket.cpp in Sources */, + A22B63CBE8E52759908258DF /* OscOutboundPacketStream.cpp in Sources */, + 1A73301C1FC30566001E730B /* xmmAttribute.cpp in Sources */, + 1A732FD31FC30566001E730B /* bbpr.cpp in Sources */, + 1A7330271FC30566001E730B /* xmmHmmParameters.cpp in Sources */, + 1A73301D1FC30566001E730B /* xmmJson.cpp in Sources */, + 1A7330041FC30566001E730B /* classification.cpp in Sources */, + 1A732FD21FC30566001E730B /* finitedifferences.c in Sources */, + 638D65104AC275AFCB576B80 /* OscPrintReceivedElements.cpp in Sources */, + 1A7330241FC30566001E730B /* xmmGmmParameters.cpp in Sources */, + 1A7330051FC30566001E730B /* dtw.cpp in Sources */, + 1A732FE31FC30566001E730B /* rta_moments.c in Sources */, + 1A73300C1FC30566001E730B /* searchWindow.cpp in Sources */, + 1A73300A1FC30566001E730B /* rapidStream.cpp in Sources */, + 1A732FD01FC30566001E730B /* BayesianFilter.cpp in Sources */, + 1A732FD41FC30566001E730B /* rpoly.cpp in Sources */, + 1A732FD91FC30566001E730B /* rta_biquad.c in Sources */, + 1A732FEA1FC30566001E730B /* PiPoCollection.cpp in Sources */, + 1A04D8C41FC31D0E00D725DC /* RapidBitalino.cpp in Sources */, + 0B9EEAF6D1EBB25B81373273 /* OscReceivedElements.cpp in Sources */, + 1A73301B1FC30566001E730B /* readme.md in Sources */, + 66078BCDF7C6B8F85391BD78 /* OscTypes.cpp in Sources */, + 1A732FDF1FC30566001E730B /* rta_lifter.c in Sources */, + 1A7330291FC30566001E730B /* xmmKMeans.cpp in Sources */, + 1A732FE91FC30566001E730B /* rta_window.c in Sources */, + 1A732FD81FC30566001E730B /* rta_bands.c in Sources */, + 1A7330201FC30566001E730B /* xmmModelSingleClass.cpp in Sources */, + 1A73301E1FC30566001E730B /* xmmGaussianDistribution.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + E4EEB9AC138B136A00A80321 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = openFrameworks; + targetProxy = E4EEB9AB138B136A00A80321 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + E4B69B4E0A3A1720003C02F2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + GCC_AUTO_VECTORIZATION = YES; + GCC_ENABLE_SSE3_EXTENSIONS = YES; + GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES; + GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; + GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + HEADER_SEARCH_PATHS = ( + "$(OF_CORE_HEADERS)", + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/posix, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/win32, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src, + ); + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "-D__MACOSX_CORE__", + "-mtune=native", + ); + SDKROOT = macosx; + }; + name = Debug; + }; + E4B69B4F0A3A1720003C02F2 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/"; + COPY_PHASE_STRIP = YES; + DEAD_CODE_STRIPPING = YES; + GCC_AUTO_VECTORIZATION = YES; + GCC_ENABLE_SSE3_EXTENSIONS = YES; + GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES; + GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_UNROLL_LOOPS = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; + GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + HEADER_SEARCH_PATHS = ( + "$(OF_CORE_HEADERS)", + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/posix, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/win32, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src, + ); + MACOSX_DEPLOYMENT_TARGET = 10.8; + OTHER_CPLUSPLUSFLAGS = ( + "-D__MACOSX_CORE__", + "-mtune=native", + ); + SDKROOT = macosx; + }; + name = Release; + }; + E4B69B600A3A1757003C02F2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */; + buildSettings = { + "CLANG_CXX_LANGUAGE_STANDARD[arch=i386]" = "c++0x"; + "CLANG_CXX_LANGUAGE_STANDARD[arch=x86_64]" = "c++0x"; + "CLANG_CXX_LIBRARY[arch=i386]" = "libc++"; + "CLANG_CXX_LIBRARY[arch=x86_64]" = "libc++"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(PROJECT_DIR)", + ); + FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../../../../../Documents/of_v0.9.8_osx_release/libs/glut/lib/osx\""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = NONE; + HEADER_SEARCH_PATHS = ( + "$(OF_CORE_HEADERS)", + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/posix, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/win32, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src, + ); + ICON = "$(ICON_NAME_DEBUG)"; + ICON_FILE = "$(ICON_FILE_PATH)$(ICON)"; + INFOPLIST_FILE = "openFrameworks-Info.plist"; + INSTALL_PATH = /Applications; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third_party_dependancies/pipo/sdk/examples/jucepipo", + "$(PROJECT_DIR)/third_party_dependancies/pipo-sdk/examples/jucepipo", + "$(PROJECT_DIR)/dependencies/Maximilian/openFrameworks/openFrameworksExamples/windows/ofMaximExampleVS2010/bin", + "$(PROJECT_DIR)/dependencies/pipo/bin/osx", + "$(PROJECT_DIR)/dependencies/pipo/examples/jucepipo", + "$(PROJECT_DIR)", + ); + PRODUCT_NAME = "$(TARGET_NAME)Debug"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + E4B69B610A3A1757003C02F2 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */; + buildSettings = { + "CLANG_CXX_LANGUAGE_STANDARD[arch=i386]" = "c++0x"; + "CLANG_CXX_LANGUAGE_STANDARD[arch=x86_64]" = "c++0x"; + "CLANG_CXX_LIBRARY[arch=i386]" = "libc++"; + "CLANG_CXX_LIBRARY[arch=x86_64]" = "libc++"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(PROJECT_DIR)", + ); + FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../../../../../Documents/of_v0.9.8_osx_release/libs/glut/lib/osx\""; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = NONE; + HEADER_SEARCH_PATHS = ( + "$(OF_CORE_HEADERS)", + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxGui/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxMaxim/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/posix, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/ip/win32, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/libs/oscpack/src/osc, + ../../../../../Documents/of_v0.9.8_osx_release/addons/ofxOsc/src, + ); + ICON = "$(ICON_NAME_RELEASE)"; + ICON_FILE = "$(ICON_FILE_PATH)$(ICON)"; + INFOPLIST_FILE = "openFrameworks-Info.plist"; + INSTALL_PATH = /Applications; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third_party_dependancies/pipo/sdk/examples/jucepipo", + "$(PROJECT_DIR)/third_party_dependancies/pipo-sdk/examples/jucepipo", + "$(PROJECT_DIR)/dependencies/Maximilian/openFrameworks/openFrameworksExamples/windows/ofMaximExampleVS2010/bin", + "$(PROJECT_DIR)/dependencies/pipo/bin/osx", + "$(PROJECT_DIR)/dependencies/pipo/examples/jucepipo", + "$(PROJECT_DIR)", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + baseConfigurationReference = E4EB6923138AFD0F00A09F29; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "Bitalino" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E4B69B4E0A3A1720003C02F2 /* Debug */, + E4B69B4F0A3A1720003C02F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E4B69B5F0A3A1757003C02F2 /* Build configuration list for PBXNativeTarget "Bitalino" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E4B69B600A3A1757003C02F2 /* Debug */, + E4B69B610A3A1757003C02F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E4B69B4C0A3A1720003C02F2 /* Project object */; +} diff --git a/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000000000000000000000000000000..919434a6254f0e9651f402737811be6634a03e9c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:"> + </FileRef> +</Workspace> diff --git a/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/xcshareddata/xcschemes/Bitalino Debug.xcscheme b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/xcshareddata/xcschemes/Bitalino Debug.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..b82151e07f3eda36d245533c7b1f78f509af192c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/xcshareddata/xcschemes/Bitalino Debug.xcscheme @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0600" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Debug"> + <Testables> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Debug" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <BuildableProductRunnable> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Debug" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Debug" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/xcshareddata/xcschemes/Bitalino Release.xcscheme b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/xcshareddata/xcschemes/Bitalino Release.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..6f5bb4493ff93dadcd3fa3be402aedb7ff2a5868 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/Bitalino.xcodeproj/xcshareddata/xcschemes/Bitalino Release.xcscheme @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0600" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Release"> + <Testables> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <BuildableProductRunnable> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2" + BuildableName = "Bitalino.app" + BlueprintName = "Bitalino" + ReferencedContainer = "container:Bitalino.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Release"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/examples/ofx/Bitalino_rapidmix/Makefile b/examples/ofx/Bitalino_rapidmix/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7ea4333cd79ce2e7742fbd706ac6d36bd928530f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/Makefile @@ -0,0 +1,13 @@ +# Attempt to load a config.make file. +# If none is found, project defaults in config.project.make will be used. +ifneq ($(wildcard config.make),) + include config.make +endif + +# make sure the the OF_ROOT location is defined +ifndef OF_ROOT + OF_ROOT=$(realpath ../../../../../Documents/of_v0.9.8_osx_release) +endif + +# call the project makefile! +include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk diff --git a/examples/ofx/Bitalino_rapidmix/Project.xcconfig b/examples/ofx/Bitalino_rapidmix/Project.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..9097ebacaaced2294edf9b16734b17eaada53dad --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/Project.xcconfig @@ -0,0 +1,17 @@ +//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT. +//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED +OF_PATH = ../../../../../Documents/of_v0.9.8_osx_release + +//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE +#include "../../../../../Documents/of_v0.9.8_osx_release/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig" + +//ICONS - NEW IN 0072 +ICON_NAME_DEBUG = icon-debug.icns +ICON_NAME_RELEASE = icon.icns +ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/ + +//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to: +//ICON_FILE_PATH = bin/data/ + +OTHER_LDFLAGS = $(OF_CORE_LIBS) $(OF_CORE_FRAMEWORKS) +HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) diff --git a/examples/ofx/Bitalino_rapidmix/addons.make b/examples/ofx/Bitalino_rapidmix/addons.make new file mode 100644 index 0000000000000000000000000000000000000000..2d84199324faf17991032ebca2b8a99c0ee4cea5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/addons.make @@ -0,0 +1,3 @@ +ofxGui +ofxMaxim +ofxOsc diff --git a/examples/ofx/Bitalino_rapidmix/bin/data/.gitkeep b/examples/ofx/Bitalino_rapidmix/bin/data/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/ofx/Bitalino_rapidmix/config.make b/examples/ofx/Bitalino_rapidmix/config.make new file mode 100644 index 0000000000000000000000000000000000000000..963b07d12f6843f2b51ea8e0ebe2d80318292e7b --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/config.make @@ -0,0 +1,142 @@ +################################################################################ +# CONFIGURE PROJECT MAKEFILE (optional) +# This file is where we make project specific configurations. +################################################################################ + +################################################################################ +# OF ROOT +# The location of your root openFrameworks installation +# (default) OF_ROOT = ../../../../../Documents/of_v0.9.8_osx_release +################################################################################ +# OF_ROOT = ../../../../../Documents/of_v0.9.8_osx_release + +################################################################################ +# PROJECT ROOT +# The location of the project - a starting place for searching for files +# (default) PROJECT_ROOT = . (this directory) +# +################################################################################ +# PROJECT_ROOT = . + +################################################################################ +# PROJECT SPECIFIC CHECKS +# This is a project defined section to create internal makefile flags to +# conditionally enable or disable the addition of various features within +# this makefile. For instance, if you want to make changes based on whether +# GTK is installed, one might test that here and create a variable to check. +################################################################################ +# None + +################################################################################ +# PROJECT EXTERNAL SOURCE PATHS +# These are fully qualified paths that are not within the PROJECT_ROOT folder. +# Like source folders in the PROJECT_ROOT, these paths are subject to +# exlclusion via the PROJECT_EXLCUSIONS list. +# +# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXTERNAL_SOURCE_PATHS = + +################################################################################ +# PROJECT EXCLUSIONS +# These makefiles assume that all folders in your current project directory +# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations +# to look for source code. The any folders or files that match any of the +# items in the PROJECT_EXCLUSIONS list below will be ignored. +# +# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete +# string unless teh user adds a wildcard (%) operator to match subdirectories. +# GNU make only allows one wildcard for matching. The second wildcard (%) is +# treated literally. +# +# (default) PROJECT_EXCLUSIONS = (blank) +# +# Will automatically exclude the following: +# +# $(PROJECT_ROOT)/bin% +# $(PROJECT_ROOT)/obj% +# $(PROJECT_ROOT)/%.xcodeproj +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXCLUSIONS = + +################################################################################ +# PROJECT LINKER FLAGS +# These flags will be sent to the linker when compiling the executable. +# +# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ + +# Currently, shared libraries that are needed are copied to the +# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to +# add a runtime path to search for those shared libraries, since they aren't +# incorporated directly into the final executable application binary. +# TODO: should this be a default setting? +# PROJECT_LDFLAGS=-Wl,-rpath=./libs + +################################################################################ +# PROJECT DEFINES +# Create a space-delimited list of DEFINES. The list will be converted into +# CFLAGS with the "-D" flag later in the makefile. +# +# (default) PROJECT_DEFINES = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_DEFINES = + +################################################################################ +# PROJECT CFLAGS +# This is a list of fully qualified CFLAGS required when compiling for this +# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS +# defined in your platform specific core configuration files. These flags are +# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. +# +# (default) PROJECT_CFLAGS = (blank) +# +# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in +# your platform specific configuration file will be applied by default and +# further flags here may not be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CFLAGS = + +################################################################################ +# PROJECT OPTIMIZATION CFLAGS +# These are lists of CFLAGS that are target-specific. While any flags could +# be conditionally added, they are usually limited to optimization flags. +# These flags are added BEFORE the PROJECT_CFLAGS. +# +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) +# +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) +# +# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the +# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration +# file will be applied by default and further optimization flags here may not +# be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = + +################################################################################ +# PROJECT COMPILERS +# Custom compilers can be set for CC and CXX +# (default) PROJECT_CXX = (blank) +# (default) PROJECT_CC = (blank) +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CXX = +# PROJECT_CC = diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVF.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVF.cpp new file mode 100755 index 0000000000000000000000000000000000000000..36ef7d53af50be299a2295bd55d14d3585ea0ea1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVF.cpp @@ -0,0 +1,1375 @@ +/** + * Gesture Variation Follower class allows for early gesture recognition and variation tracking + * + * @details Original algorithm designed and implemented in 2011 at Ircam Centre Pompidou + * by Baptiste Caramiaux and Nicola Montecchio. The library has been created and is maintained by Baptiste Caramiaux + * + * Copyright (C) 2015 Baptiste Caramiaux, Nicola Montecchio + * STMS lab Ircam-CRNS-UPMC, University of Padova, Goldsmiths College University of London + * + * The library is under the GNU Lesser General Public License (LGPL v3) + */ + +#include "GVF.h" +#include <string.h> +#include <stdio.h> +#include <iostream> +#include <fstream> +#include <sstream> +#include <memory> +#include <algorithm> +#include <numeric> + +//debug max +//#include "ext.h" + + +using namespace std; + +//-------------------------------------------------------------- +GVF::GVF() +{ + config.inputDimensions = 2; + config.translate = true; + config.segmentation = false; + + parameters.numberParticles = 1000; + parameters.tolerance = 0.2f; + parameters.resamplingThreshold = 250; + parameters.distribution = 0.0f; + parameters.alignmentVariance = sqrt(0.000001f); + parameters.dynamicsVariance = vector<float>(1,sqrt(0.001f)); + parameters.scalingsVariance = vector<float>(1,sqrt(0.00001f)); + parameters.rotationsVariance = vector<float>(1,sqrt(0.0f)); + parameters.predictionSteps = 1; + parameters.dimWeights = vector<float>(1,sqrt(1.0f)); + parameters.alignmentSpreadingCenter = 0.0; + parameters.alignmentSpreadingRange = 0.2; + parameters.dynamicsSpreadingCenter = 1.0; + parameters.dynamicsSpreadingRange = 0.3; + parameters.scalingsSpreadingCenter = 1.0; + parameters.scalingsSpreadingRange = 0.3; + parameters.rotationsSpreadingCenter = 0.0; + parameters.rotationsSpreadingRange = 0.5; + + tolerancesetmanually = false; + learningGesture = -1; + + normgen = std::mt19937(rd()); + rndnorm = new std::normal_distribution<float>(0.0,1.0); + unifgen = std::default_random_engine(rd()); + rndunif = new std::uniform_real_distribution<float>(0.0,1.0); + +} + +////-------------------------------------------------------------- +//GVF::GVF(GVFConfig _config){ +// setup(_config); +//} +// +////-------------------------------------------------------------- +//GVF::GVF(GVFConfig _config, GVFParameters _parameters){ +// setup(_config, _parameters); +//} +// +////-------------------------------------------------------------- +//void GVF::setup(){ +// +// // use defualt parameters +// GVFConfig defaultConfig; +// +// defaultConfig.inputDimensions = 2; +// defaultConfig.translate = true; +// defaultConfig.segmentation = false; +// +// setup(defaultConfig); +//} +// +////-------------------------------------------------------------- +//void GVF::setup(GVFConfig _config){ +// +// clear(); // just in case +// +// learningGesture = -1; +// +// // Set configuration: +// config = _config; +// +// // default parameters +// GVFParameters defaultParameters; +// defaultParameters.numberParticles = 1000; +// defaultParameters.tolerance = 0.2f; +// defaultParameters.resamplingThreshold = 250; +// defaultParameters.distribution = 0.0f; +// defaultParameters.alignmentVariance = sqrt(0.000001f); +// defaultParameters.dynamicsVariance = vector<float>(1,sqrt(0.001f)); +// defaultParameters.scalingsVariance = vector<float>(1,sqrt(0.00001f)); +// defaultParameters.rotationsVariance = vector<float>(1,sqrt(0.0f)); +// defaultParameters.predictionSteps = 1; +// defaultParameters.dimWeights = vector<float>(1,sqrt(1.0f)); +// +// // default spreading +// defaultParameters.alignmentSpreadingCenter = 0.0; +// defaultParameters.alignmentSpreadingRange = 0.2; +// +// defaultParameters.dynamicsSpreadingCenter = 1.0; +// defaultParameters.dynamicsSpreadingRange = 0.3; +// +// defaultParameters.scalingsSpreadingCenter = 1.0; +// defaultParameters.scalingsSpreadingRange = 0.3; +// +// defaultParameters.rotationsSpreadingCenter = 0.0; +// defaultParameters.rotationsSpreadingRange = 0.0; +// +// tolerancesetmanually = false; +// +// setup(_config, defaultParameters); +// +//} +// +////-------------------------------------------------------------- +//void GVF::setup(GVFConfig _config, GVFParameters _parameters) +//{ +// clear(); // just in case +// // Set configuration and parameters +// config = _config; +// parameters = _parameters; +// // Init random generators +// normgen = std::mt19937(rd()); +// rndnorm = new std::normal_distribution<float>(0.0,1.0); +// unifgen = std::default_random_engine(rd()); +// rndunif = new std::uniform_real_distribution<float>(0.0,1.0); +//} + +//-------------------------------------------------------------- +GVF::~GVF() +{ + if (rndnorm != NULL) + delete (rndnorm); + clear(); // not really necessary but it's polite ;) +} + +//-------------------------------------------------------------- +void GVF::clear() +{ + state = STATE_CLEAR; + gestureTemplates.clear(); + mostProbableIndex = -1; +} + +//-------------------------------------------------------------- +void GVF::startGesture() +{ + if (state==STATE_FOLLOWING) + { + restart(); + } + else if (state==STATE_LEARNING) + { + if (theGesture.getNumberOfTemplates()>0) + { + if (theGesture.getTemplateLength()>0) + addGestureTemplate(theGesture); + } + theGesture.clear(); + } +} + +//-------------------------------------------------------------- +void GVF::addObservation(vector<float> data) +{ + theGesture.addObservation(data); +} + +//-------------------------------------------------------------- +void GVF::addGestureTemplate(GVFGesture & gestureTemplate) +{ + + // if (getState() != GVF::STATE_LEARNING) + // setState(GVF::STATE_LEARNING); + + int inputDimension = gestureTemplate.getNumberDimensions(); + config.inputDimensions = inputDimension; + + gestureTemplates.push_back(gestureTemplate); + activeGestures.push_back(gestureTemplates.size()); + + if(minRange.size() == 0){ + minRange.resize(inputDimension); + maxRange.resize(inputDimension); + } + + for(int j = 0; j < inputDimension; j++){ + minRange[j] = INFINITY; + maxRange[j] = -INFINITY; + } + + // compute min/max from the data + for(int i = 0; i < gestureTemplates.size(); i++){ + GVFGesture& tGestureTemplate = gestureTemplates[i]; + vector<float>& tMinRange = tGestureTemplate.getMinRange(); + vector<float>& tMaxRange = tGestureTemplate.getMaxRange(); + for(int j = 0; j < inputDimension; j++){ + if(tMinRange[j] < minRange[j]) minRange[j] = tMinRange[j]; + if(tMaxRange[j] > maxRange[j]) maxRange[j] = tMaxRange[j]; + } + } + + for(int i = 0; i < gestureTemplates.size(); i++){ + GVFGesture& tGestureTemplate = gestureTemplates[i]; + tGestureTemplate.setMinRange(minRange); + tGestureTemplate.setMaxRange(maxRange); + } + train(); + +} + +//-------------------------------------------------------------- +void GVF::replaceGestureTemplate(GVFGesture & gestureTemplate, int index) +{ + if(gestureTemplate.getNumberDimensions()!=config.inputDimensions) + return; + if(minRange.size() == 0) + { + minRange.resize(config.inputDimensions); + maxRange.resize(config.inputDimensions); + } + for(int j = 0; j < config.inputDimensions; j++) + { + minRange[j] = INFINITY; + maxRange[j] = -INFINITY; + } + if (index<=gestureTemplates.size()) + gestureTemplates[index-1]=gestureTemplate; + for(int i = 0; i < gestureTemplates.size(); i++) + { + GVFGesture& tGestureTemplate = gestureTemplates[i]; + vector<float>& tMinRange = tGestureTemplate.getMinRange(); + vector<float>& tMaxRange = tGestureTemplate.getMaxRange(); + for(int j = 0; j < config.inputDimensions; j++){ + if(tMinRange[j] < minRange[j]) minRange[j] = tMinRange[j]; + if(tMaxRange[j] > maxRange[j]) maxRange[j] = tMaxRange[j]; + } + } + for(int i = 0; i < gestureTemplates.size(); i++) + { + GVFGesture& tGestureTemplate = gestureTemplates[i]; + tGestureTemplate.setMinRange(minRange); + tGestureTemplate.setMaxRange(maxRange); + } +} + +////-------------------------------------------------------------- +//vector<float>& GVF::getGestureTemplateSample(int gestureIndex, float cursor) +//{ +// int frameindex = min((int)(gestureTemplates[gestureIndex].getTemplateLength() - 1), +// (int)(floor(cursor * gestureTemplates[gestureIndex].getTemplateLength() ) ) ); +// return gestureTemplates[gestureIndex].getTemplate()[frameindex]; +//} + +//-------------------------------------------------------------- +GVFGesture & GVF::getGestureTemplate(int index){ + assert(index < gestureTemplates.size()); + return gestureTemplates[index]; +} + +//-------------------------------------------------------------- +vector<GVFGesture> & GVF::getAllGestureTemplates(){ + return gestureTemplates; +} + +//-------------------------------------------------------------- +int GVF::getNumberOfGestureTemplates(){ + return (int)gestureTemplates.size(); +} + +//-------------------------------------------------------------- +void GVF::removeGestureTemplate(int index){ + assert(index < gestureTemplates.size()); + gestureTemplates.erase(gestureTemplates.begin() + index); +} + +//-------------------------------------------------------------- +void GVF::removeAllGestureTemplates(){ + gestureTemplates.clear(); +} + +//---------------------------------------------- +void GVF::train(){ + + if (gestureTemplates.size() > 0) + { + + // get the number of dimension in templates + config.inputDimensions = gestureTemplates[0].getTemplateDimension(); + + dynamicsDim = 2; // hard coded: just speed now + scalingsDim = config.inputDimensions; + + // manage orientation + if (config.inputDimensions==2) rotationsDim=1; + else if (config.inputDimensions==3) rotationsDim=3; + else rotationsDim=0; + + // Init state space + initVec(classes, parameters.numberParticles); // Vector of gesture class + initVec(alignment, parameters.numberParticles); // Vector of phase values (alignment) + initMat(dynamics, parameters.numberParticles, dynamicsDim); // Matric of dynamics + initMat(scalings, parameters.numberParticles, scalingsDim); // Matrix of scaling + if (rotationsDim!=0) initMat(rotations, parameters.numberParticles, rotationsDim); // Matrix of rotations + initMat(offsets, parameters.numberParticles, config.inputDimensions); + initVec(weights, parameters.numberParticles); // Weights + + initMat(particles, parameters.numberParticles, 3); + // std::cout << particles.size() << " " << parameters.numberParticles << std::endl; + + // bayesian elements + initVec(prior, parameters.numberParticles); + initVec(posterior, parameters.numberParticles); + initVec(likelihood, parameters.numberParticles); + + + initPrior(); // prior on init state values + initNoiseParameters(); // init noise parameters (transition and likelihood) + + + // weighted dimensions in case: default is not weighted + if (parameters.dimWeights.size()!=config.inputDimensions){ + parameters.dimWeights = vector<float> (config.inputDimensions); + for(int k = 0; k < config.inputDimensions; k++) parameters.dimWeights[k] = 1.0 / config.inputDimensions; + } + + // NORMALIZATION +// if (config.normalization) { // update the global normaliation factor +// globalNormalizationFactor = -1.0; +// // loop on previous gestures already learned +// // take the max of all the gesture learned ... +// for (int k=0; k<getNumberOfGestureTemplates() ; k++){ +// for(int j = 0; j < config.inputDimensions; j++){ +// float rangetmp = fabs(getGestureTemplate(k).getMaxRange()[j]-getGestureTemplate(k).getMinRange()[j]); +// if (rangetmp > globalNormalizationFactor) +// globalNormalizationFactor=rangetmp; +// } +// } +// } +// // only for logs +// if (config.logOn) { +// vecRef = vector<vector<float> > (parameters.numberParticles); +// vecObs = vector<float> (config.inputDimensions); +// stateNoiseDist = vector<float> (parameters.numberParticles); +// } + } +} + +//-------------------------------------------------------------- +//void GVF::initPrior() +//{ +// +// // PATICLE FILTERING +// for (int k = 0; k < parameters.numberParticles; k++) +// { +// initPrior(k); +// +// classes[k] = activeGestures[k % activeGestures.size()] - 1; +// } +// +//} + +//-------------------------------------------------------------- +void GVF::initPrior() //int pf_n) +{ + for (int pf_n = 0; pf_n < parameters.numberParticles; pf_n++) + { + // alignment + alignment[pf_n] = ((*rndunif)(unifgen) - 0.5) * parameters.alignmentSpreadingRange + parameters.alignmentSpreadingCenter; // spread phase + + + // dynamics + dynamics[pf_n][0] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange + parameters.dynamicsSpreadingCenter; // spread speed + if (dynamics[pf_n].size()>1) + { + dynamics[pf_n][1] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange; // spread accel + } + + // scalings + for(int l = 0; l < scalings[pf_n].size(); l++) { + scalings[pf_n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.scalingsSpreadingRange + parameters.scalingsSpreadingCenter; // spread scalings + } + + // rotations + if (rotationsDim!=0) + for(int l = 0; l < rotations[pf_n].size(); l++) + rotations[pf_n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.rotationsSpreadingRange + parameters.rotationsSpreadingCenter; // spread rotations + + if (config.translate) for(int l = 0; l < offsets[pf_n].size(); l++) offsets[pf_n][l] = 0.0; + + + prior[pf_n] = 1.0 / (float) parameters.numberParticles; + + // set the posterior to the prior at the initialization + posterior[pf_n] = prior[pf_n]; + + classes[pf_n] = activeGestures[pf_n % activeGestures.size()] - 1; + } + +} + +//-------------------------------------------------------------- +void GVF::initNoiseParameters() { + + // NOISE (ADDITIVE GAUSSIAN NOISE) + // --------------------------- + + if (parameters.dynamicsVariance.size() != dynamicsDim) + { + float variance = parameters.dynamicsVariance[0]; + parameters.dynamicsVariance.resize(dynamicsDim); + for (int k=0; k<dynamicsDim; k++) + parameters.dynamicsVariance[k] = variance; + } + + if (parameters.scalingsVariance.size() != scalingsDim) + { + float variance = parameters.scalingsVariance[0]; + parameters.scalingsVariance.resize(scalingsDim); + for (int k=0; k<scalingsDim; k++) + parameters.scalingsVariance[k] = variance; + } + + if (rotationsDim!=0) + { + if (parameters.rotationsVariance.size() != rotationsDim) + { + float variance = parameters.rotationsVariance[0]; + parameters.rotationsVariance.resize(rotationsDim); + for (int k=0; k<rotationsDim; k++) + parameters.rotationsVariance[k] = variance; + } + } + + // ADAPTATION OF THE TOLERANCE IF DEFAULT PARAMTERS + // --------------------------- + if (!tolerancesetmanually){ + float obsMeanRange = 0.0f; + for (int gt=0; gt<gestureTemplates.size(); gt++) { + for (int d=0; d<config.inputDimensions; d++) + obsMeanRange += (gestureTemplates[gt].getMaxRange()[d] - gestureTemplates[gt].getMinRange()[d]) + /config.inputDimensions; + } + obsMeanRange /= gestureTemplates.size(); + parameters.tolerance = obsMeanRange / 4.0f; // dividing by an heuristic factor [to be learned?] + } +} + +//-------------------------------------------------------------- +void GVF::setState(GVFState _state, vector<int> indexes) +{ + switch (_state) + { + case STATE_CLEAR: + clear(); + theGesture.clear(); + break; + + case STATE_LEARNING: + if ((state==STATE_LEARNING) && (theGesture.getNumberOfTemplates()>0)) + { + if (learningGesture==-1) + addGestureTemplate(theGesture); + else + { + replaceGestureTemplate(theGesture, learningGesture); + learningGesture=-1; + } + if (indexes.size()!=0) + learningGesture=indexes[0]; + } + state = _state; + theGesture.clear(); + break; + + case STATE_FOLLOWING: + if ((state==STATE_LEARNING) && (theGesture.getNumberOfTemplates()>0)) + { + if (learningGesture==-1) + addGestureTemplate(theGesture); + else + { + replaceGestureTemplate(theGesture, learningGesture); + learningGesture=-1; + } + } + if (gestureTemplates.size() > 0) + { + train(); + state = _state; + } + else + state = STATE_CLEAR; + theGesture.clear(); + break; + + default: + theGesture.clear(); + break; + } +} + +//-------------------------------------------------------------- +GVF::GVFState GVF::getState() +{ + return state; +} + +////-------------------------------------------------------------- +//int GVF::getDynamicsDimension(){ +// return dynamicsDim; +//} + +//-------------------------------------------------------------- +vector<int> GVF::getGestureClasses() +{ + return classes; +} + +////-------------------------------------------------------------- +//vector<float> GVF::getAlignment(){ +// return alignment; +//} +// +////-------------------------------------------------------------- +//vector<float> GVF::getEstimatedAlignment(){ +// return estimatedAlignment; +//} +// +////-------------------------------------------------------------- +//vector< vector<float> > GVF::getDynamics(){ +// return dynamics; +//} +// +////-------------------------------------------------------------- +//vector< vector<float> > GVF::getEstimatedDynamics(){ +// return estimatedDynamics; +//} +// +////-------------------------------------------------------------- +//vector< vector<float> > GVF::getScalings(){ +// return scalings; +//} +// +////-------------------------------------------------------------- +//vector< vector<float> > GVF::getEstimatedScalings(){ +// return estimatedScalings; +//} +// +////-------------------------------------------------------------- +//vector< vector<float> > GVF::getRotations(){ +// return rotations; +//} +// +////-------------------------------------------------------------- +//vector< vector<float> > GVF::getEstimatedRotations(){ +// return estimatedRotations; +//} + +////-------------------------------------------------------------- +//vector<float> GVF::getEstimatedProbabilities(){ +// return estimatedProbabilities; +//} +// +////-------------------------------------------------------------- +//vector<float> GVF::getEstimatedLikelihoods(){ +// return estimatedLikelihoods; +//} +// +////-------------------------------------------------------------- +//vector<float> GVF::getWeights(){ +// return weights; +//} +// +////-------------------------------------------------------------- +//vector<float> GVF::getPrior(){ +// return prior; +//} + +////-------------------------------------------------------------- +//vector<vector<float> > GVF::getVecRef() { +// return vecRef; +//} +// +////-------------------------------------------------------------- +//vector<float> GVF::getVecObs() { +// return vecObs; +//} +// +////-------------------------------------------------------------- +//vector<float> GVF::getStateNoiseDist(){ +// return stateNoiseDist; +//} + +////-------------------------------------------------------------- +//int GVF::getScalingsDim(){ +// return scalingsDim; +//} +// +////-------------------------------------------------------------- +//int GVF::getRotationsDim(){ +// return rotationsDim; +//} + +//-------------------------------------------------------------- +void GVF::restart() +{ + theGesture.clear(); + initPrior(); +} + +#pragma mark - PARTICLE FILTERING + +//-------------------------------------------------------------- +void GVF::updatePrior(int n) { + + // Update alignment / dynamics / scalings + float L = gestureTemplates[classes[n]].getTemplateLength(); + alignment[n] += (*rndnorm)(normgen) * parameters.alignmentVariance + dynamics[n][0]/L; // + dynamics[n][1]/(L*L); + + if (dynamics[n].size()>1){ + dynamics[n][0] += (*rndnorm)(normgen) * parameters.dynamicsVariance[0] + dynamics[n][1]/L; + dynamics[n][1] += (*rndnorm)(normgen) * parameters.dynamicsVariance[1]; + } + else { + dynamics[n][0] += (*rndnorm)(normgen) * parameters.dynamicsVariance[0]; + } + + // for(int l= 0; l < dynamics[n].size(); l++) dynamics[n][l] += (*rndnorm)(normgen) * parameters.dynamicsVariance[l]; + for(int l= 0; l < scalings[n].size(); l++) scalings[n][l] += (*rndnorm)(normgen) * parameters.scalingsVariance[l]; + if (rotationsDim!=0) for(int l= 0; l < rotations[n].size(); l++) rotations[n][l] += (*rndnorm)(normgen) * parameters.rotationsVariance[l]; + + // update prior (bayesian incremental inference) + prior[n] = posterior[n]; +} + +//-------------------------------------------------------------- +void GVF::updateLikelihood(vector<float> obs, int n) +{ + +// if (config.normalization) for (int kk=0; kk<vobs.size(); kk++) vobs[kk] = vobs[kk] / globalNormalizationFactor; + + if(alignment[n] < 0.0) + { + alignment[n] = fabs(alignment[n]); // re-spread at the beginning +// if (config.segmentation) +// classes[n] = n % getNumberOfGestureTemplates(); + } + else if(alignment[n] > 1.0) + { + if (config.segmentation) + { +// alignment[n] = fabs(1.0-alignment[n]); // re-spread at the beginning + alignment[n] = fabs((*rndunif)(unifgen) * 0.5); // + classes[n] = n % getNumberOfGestureTemplates(); + offsets[n] = obs; + // dynamics + dynamics[n][0] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange + parameters.dynamicsSpreadingCenter; // spread speed + if (dynamics[n].size()>1) + dynamics[n][1] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange; + // scalings + for(int l = 0; l < scalings[n].size(); l++) + scalings[n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.scalingsSpreadingRange + parameters.scalingsSpreadingCenter; // spread scalings + // rotations + if (rotationsDim!=0) + for(int l = 0; l < rotations[n].size(); l++) + rotations[n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.rotationsSpreadingRange + parameters.rotationsSpreadingCenter; // spread rotations + // prior + prior[n] = 1/(float)parameters.numberParticles; + } + else{ + alignment[n] = fabs(2.0-alignment[n]); // re-spread at the end + } + } + + vector<float> vobs(config.inputDimensions); + setVec(vobs, obs); + + if (config.translate) + for (int j=0; j < config.inputDimensions; j++) + vobs[j] = vobs[j] - offsets[n][j]; + + + // take vref from template at the given alignment + int gestureIndex = classes[n]; + float cursor = alignment[n]; + int frameindex = min((int)(gestureTemplates[gestureIndex].getTemplateLength() - 1), + (int)(floor(cursor * gestureTemplates[gestureIndex].getTemplateLength() ) ) ); +// return gestureTemplates[gestureIndex].getTemplate()[frameindex]; + vector<float> vref = gestureTemplates[gestureIndex].getTemplate()[frameindex];; //getGestureTemplateSample(classes[n], alignment[n]); + + // Apply scaling coefficients + for (int k=0;k < config.inputDimensions; k++) + { +// if (config.normalization) vref[k] = vref[k] / globalNormalizationFactor; + vref[k] *= scalings[n][k]; + } + + // Apply rotation coefficients + if (config.inputDimensions==2) { + float tmp0=vref[0]; float tmp1=vref[1]; + vref[0] = cos(rotations[n][0])*tmp0 - sin(rotations[n][0])*tmp1; + vref[1] = sin(rotations[n][0])*tmp0 + cos(rotations[n][0])*tmp1; + } + else if (config.inputDimensions==3) { + // Rotate template sample according to the estimated angles of rotations (3d) + vector<vector< float> > RotMatrix = getRotationMatrix3d(rotations[n][0],rotations[n][1],rotations[n][2]); + vref = multiplyMat(RotMatrix, vref); + } + + // weighted euclidean distance + float dist = distance_weightedEuclidean(vref,vobs,parameters.dimWeights); + + if(parameters.distribution == 0.0f){ // Gaussian distribution + likelihood[n] = exp(- dist * 1 / (parameters.tolerance * parameters.tolerance)); + } + else { // Student's distribution + likelihood[n] = pow(dist/parameters.distribution + 1, -parameters.distribution/2 - 1); // dimension is 2 .. pay attention if editing] + } +// // if log on keep track on vref and vobs +// if (config.logOn){ +// vecRef.push_back(vref); +// vecObs = vobs; +// } +} + +//-------------------------------------------------------------- +void GVF::updatePosterior(int n) { + posterior[n] = prior[n] * likelihood[n]; +} + +//-------------------------------------------------------------- +GVFOutcomes & GVF::update(vector<float> & observation) +{ + + if (state != GVF::STATE_FOLLOWING) setState(GVF::STATE_FOLLOWING); + + theGesture.addObservation(observation); + vector<float> obs = theGesture.getLastObservation(); + + // std::cout << obs[0] << " " << obs[0] << " " + // << gestureTemplates[0].getTemplate()[20][0] << " " << gestureTemplates[0].getTemplate()[20][1] << " " + // << gestureTemplates[1].getTemplate()[20][0] << " " << gestureTemplates[1].getTemplate()[20][1] << std::endl; + + + // for each particle: perform updates of state space / likelihood / prior (weights) + float sumw = 0.0; + for(int n = 0; n< parameters.numberParticles; n++) + { + + for (int m=0; m<parameters.predictionSteps; m++) + { + updatePrior(n); + updateLikelihood(obs, n); + updatePosterior(n); + } + + sumw += posterior[n]; // sum posterior to normalise the distrib afterwards + + particles[n][0] = alignment[n]; + particles[n][1] = scalings[n][0]; + particles[n][2] = classes[n]; + } + + // normalize the weights and compute the resampling criterion + float dotProdw = 0.0; + for (int k = 0; k < parameters.numberParticles; k++){ + posterior[k] /= sumw; + dotProdw += posterior[k] * posterior[k]; + } + // avoid degeneracy (no particles active, i.e. weight = 0) by resampling + if( (1./dotProdw) < parameters.resamplingThreshold) + resampleAccordingToWeights(obs); + + // estimate outcomes + estimates(); + + return outcomes; + +} + +//-------------------------------------------------------------- +void GVF::resampleAccordingToWeights(vector<float> obs) +{ + // covennient + int numOfPart = parameters.numberParticles; + + // cumulative dist + vector<float> c(numOfPart); + + // tmp matrices + vector<int> oldClasses; + vector<float> oldAlignment; + vector< vector<float> > oldDynamics; + vector< vector<float> > oldScalings; + vector< vector<float> > oldRotations; + + setVec(oldClasses, classes); + setVec(oldAlignment, alignment); + setMat(oldDynamics, dynamics); + setMat(oldScalings, scalings); + if (rotationsDim!=0) setMat(oldRotations, rotations); + + + c[0] = 0; + for(int i = 1; i < numOfPart; i++) c[i] = c[i-1] + posterior[i]; + + + float u0 = (*rndunif)(unifgen)/numOfPart; + + int i = 0; + for (int j = 0; j < numOfPart; j++) + { + float uj = u0 + (j + 0.) / numOfPart; + + while (uj > c[i] && i < numOfPart - 1){ + i++; + } + + classes[j] = oldClasses[i]; + alignment[j] = oldAlignment[i]; + + for (int l=0;l<dynamicsDim;l++) dynamics[j][l] = oldDynamics[i][l]; + for (int l=0;l<scalingsDim;l++) scalings[j][l] = oldScalings[i][l]; + if (rotationsDim!=0) for (int l=0;l<rotationsDim;l++) rotations[j][l] = oldRotations[i][l]; + + // update posterior (partilces' weights) + posterior[j] = 1.0/(float)numOfPart; + } + +} + + +//-------------------------------------------------------------- +void GVF::estimates(){ + + + int numOfPart = parameters.numberParticles; + vector<float> probabilityNormalisation(getNumberOfGestureTemplates()); + setVec(probabilityNormalisation, 0.0f, getNumberOfGestureTemplates()); // rows are gestures + setVec(estimatedAlignment, 0.0f, getNumberOfGestureTemplates()); // rows are gestures + setMat(estimatedDynamics, 0.0f, getNumberOfGestureTemplates(), dynamicsDim); // rows are gestures, cols are features + probabilities + setMat(estimatedScalings, 0.0f, getNumberOfGestureTemplates(), scalingsDim); // rows are gestures, cols are features + probabilities + if (rotationsDim!=0) setMat(estimatedRotations, 0.0f, getNumberOfGestureTemplates(), rotationsDim); // .. + setVec(estimatedProbabilities, 0.0f, getNumberOfGestureTemplates()); // rows are gestures + setVec(estimatedLikelihoods, 0.0f, getNumberOfGestureTemplates()); // rows are gestures + + // float sumposterior = 0.; + + for(int n = 0; n < numOfPart; n++) + { + probabilityNormalisation[classes[n]] += posterior[n]; + } + + + // compute the estimated features and likelihoods + for(int n = 0; n < numOfPart; n++) + { + + // sumposterior += posterior[n]; + estimatedAlignment[classes[n]] += alignment[n] * posterior[n]; + + for(int m = 0; m < dynamicsDim; m++) + estimatedDynamics[classes[n]][m] += dynamics[n][m] * (posterior[n]/probabilityNormalisation[classes[n]]); + + for(int m = 0; m < scalingsDim; m++) + estimatedScalings[classes[n]][m] += scalings[n][m] * (posterior[n]/probabilityNormalisation[classes[n]]); + + if (rotationsDim!=0) + for(int m = 0; m < rotationsDim; m++) + estimatedRotations[classes[n]][m] += rotations[n][m] * (posterior[n]/probabilityNormalisation[classes[n]]); + + if (!isnan(posterior[n])) + estimatedProbabilities[classes[n]] += posterior[n]; + estimatedLikelihoods[classes[n]] += likelihood[n]; + } + + // calculate most probable index during scaling... + float maxProbability = 0.0f; + mostProbableIndex = -1; + + for(int gi = 0; gi < getNumberOfGestureTemplates(); gi++) + { + if(estimatedProbabilities[gi] > maxProbability){ + maxProbability = estimatedProbabilities[gi]; + mostProbableIndex = gi; + } + } + // std::cout << estimatedProbabilities[0] << " " << estimatedProbabilities[1] << std::endl; + + // outcomes.estimations.clear(); + outcomes.likelihoods.clear(); + outcomes.alignments.clear(); + outcomes.scalings.clear(); + outcomes.dynamics.clear(); + outcomes.rotations.clear(); + + // most probable gesture index + outcomes.likeliestGesture = mostProbableIndex; + + // Fill estimation for each gesture + for (int gi = 0; gi < gestureTemplates.size(); ++gi) { + + // GVFEstimation estimation; + outcomes.likelihoods.push_back(estimatedProbabilities[gi]); + outcomes.alignments.push_back(estimatedAlignment[gi]); + // estimation.probability = estimatedProbabilities[gi]; + // estimation.alignment = estimatedAlignment[gi]; + + + vector<float> gDynamics(dynamicsDim, 0.0); + for (int j = 0; j < dynamicsDim; ++j) gDynamics[j] = estimatedDynamics[gi][j]; + outcomes.dynamics.push_back(gDynamics); + + vector<float> gScalings(scalingsDim, 0.0); + for (int j = 0; j < scalingsDim; ++j) gScalings[j] = estimatedScalings[gi][j]; + outcomes.scalings.push_back(gScalings); + + vector<float> gRotations; + if (rotationsDim!=0) + { + gRotations.resize(rotationsDim); + for (int j = 0; j < rotationsDim; ++j) gRotations[j] = estimatedRotations[gi][j]; + outcomes.rotations.push_back(gRotations); + } + + // estimation.likelihood = estimatedLikelihoods[gi]; + + // push estimation for gesture gi in outcomes + // outcomes.estimations.push_back(estimation); + } + + + // assert(outcomes.estimations.size() == gestureTemplates.size()); + +} + +////-------------------------------------------------------------- +//int GVF::getMostProbableGestureIndex() +//{ +// return mostProbableIndex; +//} + +////-------------------------------------------------------------- +//GVFOutcomes GVF::getOutcomes() +//{ +// return outcomes; +//} + +////-------------------------------------------------------------- +//GVFEstimation GVF::getTemplateRecogInfo(int templateNumber) +//{ +// if (getOutcomes().estimations.size() <= templateNumber) { +// GVFEstimation estimation; +// return estimation; // blank +// } +// else +// return getOutcomes().estimations[templateNumber]; +//} +// +////-------------------------------------------------------------- +//GVFEstimation GVF::getRecogInfoOfMostProbable() // FIXME: Rename! +//{ +// int indexMostProbable = getMostProbableGestureIndex(); +// +// if ((getState() == GVF::STATE_FOLLOWING) && (getMostProbableGestureIndex() != -1)) { +// return getTemplateRecogInfo(indexMostProbable); +// } +// else { +// GVFEstimation estimation; +// return estimation; // blank +// } +//} + + +////-------------------------------------------------------------- +//vector<float> & GVF::getGestureProbabilities() +//{ +// gestureProbabilities.resize(getNumberOfGestureTemplates()); +// setVec(gestureProbabilities, 0.0f); +// for(int n = 0; n < parameters.numberParticles; n++) +// gestureProbabilities[classes[n]] += posterior[n]; +// +// return gestureProbabilities; +//} + +//-------------------------------------------------------------- +const vector<vector<float> > & GVF::getParticlesPositions(){ + return particles; +} + +////-------------------------------------------------------------- +//void GVF::setParameters(GVFParameters _parameters){ +// +// // if the number of particles has changed, we have to re-allocate matrices +// if (_parameters.numberParticles != parameters.numberParticles) +// { +// parameters = _parameters; +// +// // minimum number of particles allowed +// if (parameters.numberParticles < 4) parameters.numberParticles = 4; +// +// // re-learn +// train(); +// +// // adapt the resampling threshold in case if RT < NS +// if (parameters.numberParticles <= parameters.resamplingThreshold) +// parameters.resamplingThreshold = parameters.numberParticles / 4; +// +// } +// else +// parameters = _parameters; +// +// +//} +// +//GVFParameters GVF::getParameters(){ +// return parameters; +//} + +//-------------------------------------------------------------- +// Update the number of particles +void GVF::setNumberOfParticles(int numberOfParticles){ + + parameters.numberParticles = numberOfParticles; + + if (parameters.numberParticles < 4) // minimum number of particles allowed + parameters.numberParticles = 4; + + train(); + + if (parameters.numberParticles <= parameters.resamplingThreshold) { + parameters.resamplingThreshold = parameters.numberParticles / 4; + } + +} + +//-------------------------------------------------------------- +int GVF::getNumberOfParticles(){ + return parameters.numberParticles; // Return the number of particles +} + +//-------------------------------------------------------------- +void GVF::setActiveGestures(vector<int> activeGestureIds) +{ + int argmax = *std::max_element(activeGestureIds.begin(), activeGestureIds.end()); + if (activeGestureIds[argmax] <= gestureTemplates.size()) + { + activeGestures = activeGestureIds; + } + else + { + activeGestures.resize(gestureTemplates.size()); + std::iota(activeGestures.begin(), activeGestures.end(), 1); + } +} + +//-------------------------------------------------------------- +void GVF::setPredictionSteps(int predictionSteps) +{ + if (predictionSteps<1) + parameters.predictionSteps = 1; + else + parameters.predictionSteps = predictionSteps; +} + +//-------------------------------------------------------------- +int GVF::getPredictionSteps() +{ + return parameters.predictionSteps; // Return the number of particles +} + +//-------------------------------------------------------------- +// Update the resampling threshold used to avoid degeneracy problem +void GVF::setResamplingThreshold(int _resamplingThreshold){ + if (_resamplingThreshold >= parameters.numberParticles) + _resamplingThreshold = floor(parameters.numberParticles/2.0f); + parameters.resamplingThreshold = _resamplingThreshold; +} + +//-------------------------------------------------------------- +// Return the resampling threshold used to avoid degeneracy problem +int GVF::getResamplingThreshold(){ + return parameters.resamplingThreshold; +} + +//-------------------------------------------------------------- +// Update the standard deviation of the observation distribution +// this value acts as a tolerance for the algorithm +// low value: less tolerant so more precise but can diverge +// high value: more tolerant so less precise but converge more easily +void GVF::setTolerance(float _tolerance){ + if (_tolerance <= 0.0) _tolerance = 0.1; + parameters.tolerance = _tolerance; + tolerancesetmanually = true; +} + +//-------------------------------------------------------------- +float GVF::getTolerance(){ + return parameters.tolerance; +} + +////-------------------------------------------------------------- +void GVF::setDistribution(float _distribution){ + //nu = _distribution; + parameters.distribution = _distribution; +} +// +////-------------------------------------------------------------- +//float GVF::getDistribution(){ +// return parameters.distribution; +//} + +//void GVF::setDimWeights(vector<float> dimWeights){ +// if (dimWeights.size()!=parameters.dimWeights.size()) +// parameters.dimWeights.resize(dimWeights.size()); +// parameters.dimWeights = dimWeights; +//} +// +//vector<float> GVF::getDimWeights(){ +// return parameters.dimWeights; +//} + + +//// VARIANCE COEFFICIENTS: PHASE +////-------------------------------------------------------------- +//void GVF::setAlignmentVariance(float alignmentVariance){ +// parameters.alignmentVariance = sqrt(alignmentVariance); +//} +////-------------------------------------------------------------- +//float GVF::getAlignmentVariance(){ +// return parameters.alignmentVariance; +//} + + +// VARIANCE COEFFICIENTS: DYNAMICS +//-------------------------------------------------------------- +//void GVF::setDynamicsVariance(float dynVariance) +//{ +// for (int k=0; k< parameters.dynamicsVariance.size(); k++) +// parameters.dynamicsVariance[k] = dynVariance; +//} +//-------------------------------------------------------------- +void GVF::setDynamicsVariance(float dynVariance, int dim) +{ + if (dim == -1) + { + for (int k=0; k< parameters.dynamicsVariance.size(); k++) + parameters.dynamicsVariance[k] = dynVariance; + } + else + { + if (dim<parameters.dynamicsVariance.size()) + parameters.dynamicsVariance[dim-1] = dynVariance; + } +} + +//-------------------------------------------------------------- +void GVF::setDynamicsVariance(vector<float> dynVariance) +{ + parameters.dynamicsVariance = dynVariance; +} +//-------------------------------------------------------------- +vector<float> GVF::getDynamicsVariance() +{ + return parameters.dynamicsVariance; +} + +//-------------------------------------------------------------- +void GVF::setScalingsVariance(float scaleVariance, int dim) +{ + if (dim == -1) + { + for (int k=0; k< parameters.scalingsVariance.size(); k++) + parameters.scalingsVariance[k] = scaleVariance; + } + else + { + if (dim<parameters.scalingsVariance.size()) + parameters.scalingsVariance[dim-1] = scaleVariance; + } +} + +//-------------------------------------------------------------- +void GVF::setScalingsVariance(vector<float> scaleVariance) +{ + parameters.scaleVariance = scaleVariance; +} + +//-------------------------------------------------------------- +vector<float> GVF::getScalingsVariance() +{ + return parameters.scalingsVariance; +} + +//-------------------------------------------------------------- +void GVF::setRotationsVariance(float rotationVariance, int dim) +{ + if (dim == -1) + { + for (int k=0; k< parameters.rotationsVariance.size(); k++) + parameters.rotationsVariance[k] = rotationVariance; + } + else + { + if (dim<parameters.rotationsVariance.size()) + parameters.scalingsVariance[dim-1] = rotationVariance; + } +} + +//-------------------------------------------------------------- +void GVF::setRotationsVariance(vector<float> rotationVariance) +{ + parameters.scaleVariance = rotationVariance; +} + +//-------------------------------------------------------------- +vector<float> GVF::getRotationsVariance() +{ + return parameters.rotationsVariance; +} + +//-------------------------------------------------------------- +void GVF::setSpreadDynamics(float center, float range, int dim) +{ + parameters.dynamicsSpreadingCenter = center; + parameters.dynamicsSpreadingRange = range; +} + +//-------------------------------------------------------------- +void GVF::setSpreadScalings(float center, float range, int dim) +{ + parameters.scalingsSpreadingCenter = center; + parameters.scalingsSpreadingRange = range; +} + +//-------------------------------------------------------------- +void GVF::setSpreadRotations(float center, float range, int dim) +{ + parameters.rotationsSpreadingCenter = center; + parameters.rotationsSpreadingRange = range; +} + +//-------------------------------------------------------------- +void GVF::translate(bool translateFlag) +{ + config.translate = translateFlag; +} + +//-------------------------------------------------------------- +void GVF::segmentation(bool segmentationFlag) +{ + config.segmentation = segmentationFlag; +} + + +// UTILITIES + +//-------------------------------------------------------------- +// Save function. This function is used by applications to save the +// vocabulary in a text file given by filename (filename is also the complete path + filename) +void GVF::saveTemplates(string filename){ + + std::string directory = filename; + + std::ofstream file_write(directory.c_str()); + + for(int i=0; i < gestureTemplates.size(); i++) // Number of gesture templates + { + file_write << "template " << i << " " << config.inputDimensions << endl; + vector<vector<float> > templateTmp = gestureTemplates[i].getTemplate(); + for(int j = 0; j < templateTmp.size(); j++) + { + for(int k = 0; k < config.inputDimensions; k++) + file_write << templateTmp[j][k] << " "; + file_write << endl; + } + } + file_write.close(); + +} + + + + +//-------------------------------------------------------------- +// Load function. This function is used by applications to load a vocabulary +// given by filename (filename is also the complete path + filename) +void GVF::loadTemplates(string filename){ + // clear(); + // + + GVFGesture loadedGesture; + loadedGesture.clear(); + + ifstream infile; + stringstream doung; + + infile.open (filename.c_str(), ifstream::in); + // + string line; + vector<string> list; + int cl = -1; + while(!infile.eof()) + { + cl++; + infile >> line; + + list.push_back(line); + } + + int k = 0; + int template_id = -1; + int template_dim = 0; + + + while (k < (list.size() - 1)){ // TODO to be changed if dim>2 + + + if (!strcmp(list[k].c_str(),"template")) + { + template_id = atoi(list[k+1].c_str()); + template_dim = atoi(list[k+2].c_str()); + k = k + 3; + + if (loadedGesture.getNumberOfTemplates() > 0){ + addGestureTemplate(loadedGesture); + loadedGesture.clear(); + } + } + + if (template_dim <= 0){ + //post("bug dim = -1"); + } + else{ + + vector<float> vect(template_dim); + + for (int kk = 0; kk < template_dim; kk++) + vect[kk] = (float) atof(list[k + kk].c_str()); + + loadedGesture.addObservation(vect); + } + k += template_dim; + + } + + if (loadedGesture.getTemplateLength() > 0){ + addGestureTemplate(loadedGesture); + loadedGesture.clear(); + } + + infile.close(); +} + + + + + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVF.h b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVF.h new file mode 100755 index 0000000000000000000000000000000000000000..647fe7c6ea372e9ec8fc265a946fb3a44c91abcc --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVF.h @@ -0,0 +1,487 @@ +/** + * Gesture Variation Follower class allows for early gesture recognition and variation tracking + * + * @details Original algorithm designed and implemented in 2011 at Ircam Centre Pompidou + * by Baptiste Caramiaux and Nicola Montecchio. The library has been created and is maintained by Baptiste Caramiaux + * + * Copyright (C) 2015 Baptiste Caramiaux, Nicola Montecchio + * STMS lab Ircam-CRNS-UPMC, University of Padova, Goldsmiths College University of London + * + * The library is under the GNU Lesser General Public License (LGPL v3) + */ + + +#ifndef _H_GVF +#define _H_GVF + +#include "GVFUtils.h" +#include "GVFGesture.h" +#include <random> +#include <iostream> +#include <iomanip> +#include <string> +#include <map> +#include <random> +#include <cmath> + + +using namespace std; + +class GVF +{ + +public: + + /** + * GVF possible states + */ + enum GVFState + { + STATE_CLEAR = 0, /**< STATE_CLEAR: clear the GVF and be in standby */ + STATE_LEARNING, /**< STATE_LEARNING: recording mode, input gestures are added to the templates */ + STATE_FOLLOWING, /**< STATE_FOLLOWING: tracking mode, input gestures are classifed and their variations tracked (need the GVF to be trained) */ + STATE_BYPASS /**< STATE_BYPASS: by pass GVF but does not erase templates or training */ + }; + + +#pragma mark - Constructors + + /** + * GVF default constructor + * @details use default configuration and parameters, can be changed using accessors + */ + GVF(); + + /** + * GVF default destructor + */ + ~GVF(); + +#pragma mark - Gesture templates + + /** + * Start a gesture either to be recorded or followed + */ + void startGesture(); + + /** + * Add an observation to a gesture template + * @details + * @param data vector of features + */ + void addObservation(vector<float> data); + + /** + * Add gesture template to the vocabulary + * + * @details a gesture template is a GVFGesture object and can be added directly to the vocabulqry or + * recorded gesture templates by using this method + * @param gestureTemplate the gesture template to be recorded + */ + void addGestureTemplate(GVFGesture & gestureTemplate); + + /** + * Replace a specific gesture template by another + * + * @param gestureTemplate the gesture template to be used + * @param index the gesture index (as integer) to be replaced + */ + void replaceGestureTemplate(GVFGesture & gestureTemplate, int index); + + /** + * Remove a specific template + * + * @param index the gesture index (as integer) to be removed + */ + void removeGestureTemplate(int index); + + /** + * Remove every recorded gesture template + */ + void removeAllGestureTemplates(); + + /** + * Get a specific gesture template a gesture template by another + * + * @param index the index of the template to be returned + * @return the template + */ + GVFGesture & getGestureTemplate(int index); + + /** + * Get every recorded gesture template + * + * @return the vecotr of gesture templates + */ + vector<GVFGesture> & getAllGestureTemplates(); + + /** + * Get number of gesture templates in the vocabulary + * @return the number of templates + */ + int getNumberOfGestureTemplates(); + + /** + * Get gesture classes + */ + vector<int> getGestureClasses(); + + +#pragma mark - Recognition and tracking + + /** + * Set the state of GVF + * @param _state the state to be given to GVF, it is a GVFState + * @param indexes an optional argument providing a list of gesture index. + * In learning mode the index of the gesture being recorded can be given as an argument + * since the type is vector<int>, it should be something like '{3}'. In following mode, the list of indexes + * is the list of active gestures to be considered in the recognition/tracking. + */ + void setState(GVFState _state, vector<int> indexes = vector<int>()); + + /** + * Return the current state of GVF + * @return GVFState the current state + */ + GVFState getState(); + + /** + * Compute the estimated gesture and its potential variations + * + * @details infers the probability that the current observation belongs to + * one of the recorded gesture template and track the variations of this gesture + * according to each template + * + * @param observation vector of the observation data at current time + * @return the estimated probabilities and variaitons relative to each template + */ + GVFOutcomes & update(vector<float> & observation); + + /** + * Define a subset of gesture templates on which to perform the recognition + * and variation tracking + * + * @details By default every recorded gesture template is considered + * @param set of gesture template index to consider + */ + void setActiveGestures(vector<int> activeGestureIds); + + /** + * Restart GVF + * @details re-sample particles at the origin (i.e. initial prior) + */ + void restart(); + + /** + * Clear GVF + * @details delete templates + */ + void clear(); + + /** + * Translate data according to the first point + * @details substract each gesture feature by the first point of the gesture + * @param boolean to activate or deactivate translation + */ + void translate(bool translateFlag); + + /** + * Segment gestures within a continuous gesture stream + * @details if segmentation is true, the method will segment a continuous gesture into a sequence + * of gestures. In other words no need to call the method startGesture(), it is done automatically + * @param segmentationFlag boolean to activate or deactivate segmentation + */ + void segmentation(bool segmentationFlag); + +#pragma mark - [ Accessors ] +#pragma mark > Parameters + /** + * Set tolerance between observation and estimation + * @details tolerance depends on the range of the data + * typially tolerance = (data range)/3.0; + * @param tolerance value + */ + void setTolerance(float tolerance); + + /** + * Get the obervation tolerance value + * @details see setTolerance(float tolerance) + * @return the current toleranc value + */ + float getTolerance(); + + void setDistribution(float _distribution); + + /** + * Set number of particles used in estimation + * @details default valye is 1000, note that the computational + * cost directly depends on the number of particles + * @param new number of particles + */ + void setNumberOfParticles(int numberOfParticles); + + /** + * Get the current number of particles + * @return the current number of particles + */ + int getNumberOfParticles(); + + /** + * Number of prediciton steps + * @details it is possible to leave GVF to perform few steps of prediction + * ahead which can be useful to estimate more fastly the variations. Default value is 1 + * which means no prediction ahead + * @param the number of prediction steps + */ + void setPredictionSteps(int predictionSteps); + + /** + * Get the current number of prediction steps + * @return current number of prediciton steps + */ + int getPredictionSteps(); + + /** + * Set resampling threshold + * @details resampling threshold is the minimum number of active particles + * before resampling all the particles by the estimated posterior distribution. + * in other words, it re-targets particles around the best current estimates + * @param the minimum number of particles (default is (number of particles)/2) + */ + void setResamplingThreshold(int resamplingThreshold); + + /** + * Get the current resampling threshold + * @return resampling threshold + */ + int getResamplingThreshold(); + +#pragma mark > Dynamics + /** + * Change variance of adaptation in dynamics + * @details if dynamics adaptation variance is high the method will adapt faster to + * fast changes in dynamics. Dynamics is 2-dimensional: the first dimension is the speed + * The second dimension is the acceleration. + * + * Typically the variance is the average amount the speed or acceleration can change from + * one sample to another. As an example, if the relative estimated speed can change from 1.1 to 1.2 + * from one sample to another, the variance should allow a change of 0.1 in speed. So the variance + * should be set to 0.1*0.1 = 0.01 + * + * @param dynVariance dynamics variance value + * @param dim optional dimension of the dynamics for which the change of variance is applied (default value is 1) + */ + void setDynamicsVariance(float dynVariance, int dim = -1); + + /** + * Change variance of adaptation in dynamics + * @details See setDynamicsVariance(float dynVariance, int dim) for more details + * @param dynVariance vector of dynamics variances, each vector index is the variance to be applied to + * each dynamics dimension (consequently the vector should be 2-dimensional). + */ + void setDynamicsVariance(vector<float> dynVariance); + + /** + * Get dynamics variances + * @return the vector of variances (the returned vector is 2-dimensional) + */ + vector<float> getDynamicsVariance(); + +#pragma mark > Scalings + /** + * Change variance of adaptation in scalings + * @details if scalings adaptation variance is high the method will adapt faster to + * fast changes in relative sizes. There is one scaling variance for each dimension + * of the input gesture. If the gesture is 2-dimensional, the scalings variances will + * also be 2-dimensional. + * + * Typically the variance is the average amount the size can change from + * one sample to another. As an example, if the relative estimated size changes from 1.1 to 1.15 + * from one sample to another, the variance should allow a change of 0.05 in size. So the variance + * should be set to 0.05*0.05 = 0.0025 + * + * @param scalings variance value + * @param dimension of the scalings for which the change of variance is applied + */ + void setScalingsVariance(float scaleVariance, int dim = -1); + + /** + * Change variance of adaptation in dynamics + * @details See setScalingsVariance(float scaleVariance, int dim) for more details + * @param vector of scalings variances, each vector index is the variance to be applied to + * each scaling dimension. + * @param vector of variances (should be the size of the template gestures dimension) + */ + void setScalingsVariance(vector<float> scaleVariance); + + /** + * Get scalings variances + * @return the vector of variances + */ + vector<float> getScalingsVariance(); + +#pragma mark > Rotations + /** + * Change variance of adaptation in orientation + * @details if rotation adaptation variance is high the method will adapt faster to + * fast changes in relative orientation. If the gesture is 2-dimensional, there is + * one variance value since the rotation can be defined by only one angle of rotation. If + * the gesture is 3-dimensional, there are 3 variance values since the rotation in 3-d is + * defined by 3 rotation angles. For any other dimension, the rotation is not defined. + * + * The variance is the average amount the orientation can change from one sample to another. + * As an example, if the relative orientation in rad changes from 0.1 to 0.2 from one observation + * to another, the variance should allow a change of 0.1 in rotation angle. So the variance + * should be set to 0.1*0.1 = 0.01 + * + * @param rotationsVariance rotation variance value + * @param dim optional dimension of the rotation for which the change of variance is applied + */ + void setRotationsVariance(float rotationsVariance, int dim = -1); + + /** + * Change variance of adaptation in orientation + * @details See setRotationsVariance(float rotationsVariance, int dim) for more details + * @param vector of rotation variances, each vector index is the variance to be applied to + * each rotation angle (1 or 3) + * @param vector of variances (should be 1 if the the template gestures are 2-dim or 3 if + * they are 3-dim) + */ + void setRotationsVariance(vector<float> rotationsVariance); + + /** + * Get rotation variances + * @return the vector of variances + */ + vector<float> getRotationsVariance(); + + +#pragma mark > Others + + /** + * Get particle values + * @return vector of list of estimated particles + */ + const vector<vector<float> > & getParticlesPositions(); + + /** + * Set the interval on which the dynamics values should be spread at the beginning (before adaptation) + * @details this interval can be used to concentrate the potential dynamics value on a narrow interval, + * typically around 1 (the default value), for instance between -0.05 and 0.05, or to allow at the very + * beginning, high changes in dynamics by spreading, for instance between 0.0 and 2.0 + * @param min lower value of the inital values for dynamics + * @param max higher value of the inital values for dynamics + * @param dim the dimension on which the change of initial interval should be applied (optional) + */ + void setSpreadDynamics(float min, float max, int dim = -1); + + /** + * Set the interval on which the scalings values should be spread at the beginning (before adaptation) + * @details this interval can be used to concentrate the potential scalings value on a narrow interval, + * typically around 1.0 (the default value), for instance between 0.95 and 1.05, or to allow at the very + * beginning high changes in dynamics by spreading, for instance, between 0.0 and 2.0 + * @param min lower value of the inital values for scalings + * @param max higher value of the inital values for scalings + * @param dim the dimension on which the change of initial interval should be applied (optional) + */ + void setSpreadScalings(float min, float max, int dim = -1); + + /** + * Set the interval on which the angle of rotation values should be spread at the beginning (before adaptation) + * @details this interval can be used to concentrate the potential angle values on a narrow interval, + * typically around 0.0 (the default value), for instance between -0.05 and 0.05, or to allow at the very + * beginning, high changes in orientation by spreading, for instance, between -0.5 and 0.5 + * @param min lower value of the inital values for angle of rotation + * @param max higher value of the inital values for angle of rotation + * @param dim the dimension on which the change of initial interval should be applied (optional) + */ + void setSpreadRotations(float min, float max, int dim = -1); + +#pragma mark - Import/Export templates + /** + * Export template data in a filename + * @param filename file name as a string + */ + void saveTemplates(string filename); + + /** + * Import template data in a filename + * @details needs to respect a given format provided by saveTemplates() + * @param file name as a string + */ + void loadTemplates(string filename); + +protected: + + GVFConfig config; // Structure storing the configuration of GVF (in GVFUtils.h) + GVFParameters parameters; // Structure storing the parameters of GVF (in GVFUtils.h) + GVFOutcomes outcomes; // Structure storing the outputs of GVF (in GVFUtils.h) + GVFState state; // State (defined above) + GVFGesture theGesture; // GVFGesture object to handle incoming data in learning and following modes + + vector<GVFGesture> gestureTemplates; // vector storing the gesture templates recorded when using the methods addObservation(vector<float> data) or addGestureTemplate(GVFGesture & gestureTemplate) + + vector<float> dimWeights; // TOOD: to be put in parameters? + vector<float> maxRange; + vector<float> minRange; + int dynamicsDim; // dynamics state dimension + int scalingsDim; // scalings state dimension + int rotationsDim; // rotation state dimension + float globalNormalizationFactor; // flagged if normalization + int mostProbableIndex; // cached most probable index + int learningGesture; + + vector<int> classes; // gesture index for each particle [ns x 1] + vector<float > alignment; // alignment index (between 0 and 1) [ns x 1] + vector<vector<float> > dynamics; // dynamics estimation [ns x 2] + vector<vector<float> > scalings; // scalings estimation [ns x D] + vector<vector<float> > rotations; // rotations estimation [ns x A] + vector<float> weights; // weight of each particle [ns x 1] + vector<float> prior; // prior of each particle [ns x 1] + vector<float> posterior; // poserior of each particle [ns x 1] + vector<float> likelihood; // likelihood of each particle [ns x 1] + + // estimations + vector<float> estimatedGesture; // .. + vector<float> estimatedAlignment; // .. + vector<vector<float> > estimatedDynamics; // .. + vector<vector<float> > estimatedScalings; // .. + vector<vector<float> > estimatedRotations; // .. + vector<float> estimatedProbabilities; // .. + vector<float> estimatedLikelihoods; // .. + vector<float> absoluteLikelihoods; // .. + + bool tolerancesetmanually; + + + vector<vector<float> > offsets; // translation offset + + vector<int> activeGestures; + + vector<float> gestureProbabilities; + vector< vector<float> > particles; + +private: + + // random number generator + std::random_device rd; + std::mt19937 normgen; + std::normal_distribution<float> *rndnorm; + std::default_random_engine unifgen; + std::uniform_real_distribution<float> *rndunif; + +#pragma mark - Private methods for model mechanics + void initPrior(); + void initNoiseParameters(); + void updateLikelihood(vector<float> obs, int n); + void updatePrior(int n); + void updatePosterior(int n); + void resampleAccordingToWeights(vector<float> obs); + void estimates(); // update estimated outcome + void train(); + + +}; + + +#endif \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVFGesture.h b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVFGesture.h new file mode 100644 index 0000000000000000000000000000000000000000..20a3fa7671a42549833d6d9e83364722fa772d06 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVFGesture.h @@ -0,0 +1,240 @@ +// +// GVFGesture.h +// gvf +// +// Created by Baptiste Caramiaux on 22/01/16. +// +// + +#ifndef GVFGesture_h +#define GVFGesture_h + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + + +class GVFGesture +{ +public: + + GVFGesture() + { + inputDimensions = 2; + setAutoAdjustRanges(true); + templatesRaw = vector<vector<vector<float > > >(); + templatesNormal = vector<vector<vector<float > > >(); + clear(); + } + + GVFGesture(int inputDimension){ + inputDimensions = inputDimension; + setAutoAdjustRanges(true); + templatesRaw = vector<vector<vector<float > > >(); + templatesNormal = vector<vector<vector<float > > >(); + clear(); + } + + ~GVFGesture(){ + clear(); + } + + void setNumberDimensions(int dimensions){ + assert(dimensions > 0); + inputDimensions = dimensions; + } + + void setAutoAdjustRanges(bool b){ + // if(b) bIsRangeMinSet = bIsRangeMaxSet = false; + bAutoAdjustNormalRange = b; + } + + void setMax(float x, float y){ + assert(inputDimensions == 2); + vector<float> r(2); + r[0] = x; r[1] = y; + setMaxRange(r); + } + + void setMin(float x, float y){ + assert(inputDimensions == 2); + vector<float> r(2); + r[0] = x; r[1] = y; + setMinRange(r); + } + + void setMax(float x, float y, float z){ + assert(inputDimensions == 3); + vector<float> r(3); + r[0] = x; r[1] = y; r[2] = z; + setMaxRange(r); + } + + void setMin(float x, float y, float z){ + assert(inputDimensions == 3); + vector<float> r(3); + r[0] = x; r[1] = y; r[2] = z; + setMinRange(r); + } + + void setMaxRange(vector<float> observationRangeMax){ + this->observationRangeMax = observationRangeMax; + // bIsRangeMaxSet = true; + normalise(); + } + + void setMinRange(vector<float> observationRangeMin){ + this->observationRangeMin = observationRangeMin; + // bIsRangeMinSet = true; + normalise(); + } + + vector<float>& getMaxRange(){ + return observationRangeMax; + } + + vector<float>& getMinRange(){ + return observationRangeMin; + } + + void autoAdjustMinMax(vector<float> & observation){ + if(observationRangeMax.size() < inputDimensions){ + observationRangeMax.assign(inputDimensions, -INFINITY); + observationRangeMin.assign(inputDimensions, INFINITY); + } + for(int i = 0; i < inputDimensions; i++){ + observationRangeMax[i] = MAX(observationRangeMax[i], observation[i]); + observationRangeMin[i] = MIN(observationRangeMin[i], observation[i]); + } + } + + void addObservation(vector<float> observation, int templateIndex = 0){ + if (observation.size() != inputDimensions) + inputDimensions = int(observation.size()); + + // check we have a valid templateIndex and correct number of input dimensions + assert(templateIndex <= templatesRaw.size()); + assert(observation.size() == inputDimensions); + + // if the template index is same as the number of temlates make a new template + if(templateIndex == templatesRaw.size()){ // make a new template + + // reserve space in raw and normal template storage + templatesRaw.resize(templatesRaw.size() + 1); + templatesNormal.resize(templatesNormal.size() + 1); + + } + + if(templatesRaw[templateIndex].size() == 0) + { + templateInitialObservation = observation; + templateInitialNormal = observation; + } + + for(int j = 0; j < observation.size(); j++) + observation[j] = observation[j] - templateInitialObservation[j]; + + // store the raw observation + templatesRaw[templateIndex].push_back(observation); + + autoAdjustMinMax(observation); + + normalise(); + } + + + + void normalise() + { + templatesNormal.resize(templatesRaw.size()); + for(int t = 0; t < templatesRaw.size(); t++) + { + templatesNormal[t].resize(templatesRaw[t].size()); + for(int o = 0; o < templatesRaw[t].size(); o++) + { + templatesNormal[t][o].resize(inputDimensions); + for(int d = 0; d < inputDimensions; d++) + { + templatesNormal[t][o][d] = templatesRaw[t][o][d] / (observationRangeMax[d] - observationRangeMin[d]); + templateInitialNormal[d] = templateInitialObservation[d] / (observationRangeMax[d] - observationRangeMin[d]); + } + } + } + } + + void setTemplate(vector< vector<float> > & observations, int templateIndex = 0){ + for(int i = 0; i < observations.size(); i++){ + addObservation(observations[i], templateIndex); + } + } + + vector< vector<float> > & getTemplate(int templateIndex = 0){ + assert(templateIndex < templatesRaw.size()); + return templatesRaw[templateIndex]; + } + + int getNumberOfTemplates(){ + return int(templatesRaw.size()); + } + + int getNumberDimensions(){ + return inputDimensions; + } + + int getTemplateLength(int templateIndex = 0){ + return int(templatesRaw[templateIndex].size()); + } + + int getTemplateDimension(int templateIndex = 0){ + return int(templatesRaw[templateIndex][0].size()); + } + + vector<float>& getLastObservation(int templateIndex = 0){ + return templatesRaw[templateIndex][templatesRaw[templateIndex].size() - 1]; + } + + vector< vector< vector<float> > >& getTemplates(){ + return templatesRaw; + } + + vector<float>& getInitialObservation(){ + return templateInitialObservation; + } + + void deleteTemplate(int templateIndex = 0) + { + assert(templateIndex < templatesRaw.size()); + templatesRaw[templateIndex].clear(); + templatesNormal[templateIndex].clear(); + } + + void clear() + { + templatesRaw.clear(); + templatesNormal.clear(); + observationRangeMax.assign(inputDimensions, -INFINITY); + observationRangeMin.assign(inputDimensions, INFINITY); + } + +private: + + int inputDimensions; + bool bAutoAdjustNormalRange; + + vector<float> observationRangeMax; + vector<float> observationRangeMin; + + vector<float> templateInitialObservation; + vector<float> templateInitialNormal; + + vector< vector< vector<float> > > templatesRaw; + vector< vector< vector<float> > > templatesNormal; + + vector<vector<float> > gestureDataFromFile; +}; + +#endif /* GVFGesture_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVFUtils.h b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVFUtils.h new file mode 100755 index 0000000000000000000000000000000000000000..28c5270bb5c11840e463d8cf19cd14c16b42a7e3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/GVFUtils.h @@ -0,0 +1,309 @@ +// +// GVFTypesAndUtils.h +// +// +// + +#ifndef __H_GVFTYPES +#define __H_GVFTYPES + +#include <map> +#include <vector> +#include <iostream> +#include <random> +#include <iostream> +#include <math.h> +#include <assert.h> + +using namespace std; + +/** + * Configuration structure + */ +typedef struct +{ + int inputDimensions; /**< input dimesnion */ + bool translate; /**< translate flag */ + bool segmentation; /**< segmentation flag */ +} GVFConfig; + +/** + * Parameters structure + */ +typedef struct +{ + float tolerance; /**< input dimesnion */ + float distribution; + int numberParticles; + int resamplingThreshold; + float alignmentVariance; + float speedVariance; + vector<float> scaleVariance; + vector<float> dynamicsVariance; + vector<float> scalingsVariance; + vector<float> rotationsVariance; + // spreadings + float alignmentSpreadingCenter; + float alignmentSpreadingRange; + float dynamicsSpreadingCenter; + float dynamicsSpreadingRange; + float scalingsSpreadingCenter; + float scalingsSpreadingRange; + float rotationsSpreadingCenter; + float rotationsSpreadingRange; + + int predictionSteps; + vector<float> dimWeights; +} GVFParameters; + +// Outcomes structure +typedef struct +{ + int likeliestGesture; + vector<float> likelihoods; + vector<float> alignments; + vector<vector<float> > dynamics; + vector<vector<float> > scalings; + vector<vector<float> > rotations; +} GVFOutcomes; + + +//-------------------------------------------------------------- +// init matrix by allocating memory +template <typename T> +inline void initMat(vector< vector<T> > & M, int rows, int cols){ + M.resize(rows); + for (int n=0; n<rows; n++){ + M[n].resize(cols); + } +} + +//-------------------------------------------------------------- +// init matrix and copy values from another matrix +template <typename T> +inline void setMat(vector< vector<T> > & C, vector< vector<float> > & M){ + int rows = int(M.size()); + int cols = int(M[0].size()); + //C.resize(rows); + C = vector<vector<T> >(rows); + for (int n=0; n<rows; n++){ + //C[n].resize(cols); + C[n] = vector<T>(cols); + for (int m=0;m<cols;m++){ + C[n][m] = M[n][m]; + } + } +} + +//-------------------------------------------------------------- +// init matrix by allocating memory and fill with T value +template <typename T> +inline void setMat(vector< vector<T> > & M, T value, int rows, int cols){ + M.resize(rows); + for (int n=0; n<rows; n++){ + M[n].resize(cols); + for (int m=0; m<cols; m++){ + M[n][m] = value; + } + } +} + +//-------------------------------------------------------------- +// set matrix filled with T value +template <typename T> +inline void setMat(vector< vector<T> > & M, T value){ + for (int n=0; n<M.size(); n++){ + for (int m=0; m<M[n].size(); m++){ + M[n][m] = value; + } + } +} + +//-------------------------------------------------------------- +template <typename T> +inline void printMat(vector< vector<T> > & M){ + for (int k=0; k<M.size(); k++){ + cout << k << ": "; + for (int l=0; l<M[0].size(); l++){ + cout << M[k][l] << " "; + } + cout << endl; + } + cout << endl; +} + +//-------------------------------------------------------------- +template <typename T> +inline void printVec(vector<T> & V){ + for (int k=0; k<V.size(); k++){ + cout << k << ": " << V[k] << (k == V.size() - 1 ? "" : " ,"); + } + cout << endl; +} + +//-------------------------------------------------------------- +template <typename T> +inline void initVec(vector<T> & V, int rows){ + V.resize(rows); +} + +//-------------------------------------------------------------- +template <typename T> +inline void setVec(vector<T> & C, vector<int> &V){ + int rows = int(V.size()); + C = vector<T>(rows); + //C.resize(rows); + for (int n=0; n<rows; n++){ + C[n] = V[n]; + } +} + +//-------------------------------------------------------------- +template <typename T> +inline void setVec(vector<T> & C, vector<float> & V){ + int rows = int(V.size()); + C.resize(rows); + for (int n=0; n<rows; n++){ + C[n] = V[n]; + } +} + +//-------------------------------------------------------------- +template <typename T> +inline void setVec(vector<T> & V, T value){ + for (int n=0; n<V.size(); n++){ + V[n] = value; + } +} + +//-------------------------------------------------------------- +template <typename T> +inline void setVec(vector<T> & V, T value, int rows){ + V.resize(rows); + setVec(V, value); +} + +//-------------------------------------------------------------- +template <typename T> +inline vector< vector<T> > dotMat(vector< vector<T> > & M1, vector< vector<T> > & M2){ + // TODO(Baptiste) +} + +//-------------------------------------------------------------- +template <typename T> +inline vector< vector<T> > multiplyMatf(vector< vector<T> > & M1, T v){ + vector< vector<T> > multiply; + initMat(multiply, M1.size(), M1[0].size()); + for (int i=0; i<M1.size(); i++){ + for (int j=0; j<M1[i].size(); j++){ + multiply[i][j] = M1[i][j] * v; + } + } + return multiply; +} + +//-------------------------------------------------------------- +template <typename T> +inline vector< vector<T> > multiplyMatf(vector< vector<T> > & M1, vector< vector<T> > & M2){ + assert(M1[0].size() == M2.size()); // columns in M1 == rows in M2 + vector< vector<T> > multiply; + initMat(multiply, M1.size(), M2[0].size()); // rows in M1 x cols in M2 + for (int i=0; i<M1.size(); i++){ + for (int j=0; j<M2[i].size(); j++){ + multiply[i][j] = 0.0f; + for(int k=0; k<M1[0].size(); k++){ + multiply[i][j] += M1[i][k] * M2[k][j]; + } + + } + } + return multiply; +} + +//-------------------------------------------------------------- +template <typename T> +inline vector<T> multiplyMat(vector< vector<T> > & M1, vector< T> & Vect){ + assert(Vect.size() == M1[0].size()); // columns in M1 == rows in Vect + vector<T> multiply; + initVec(multiply, Vect.size()); + for (int i=0; i<M1.size(); i++){ + multiply[i] = 0.0f; + for (int j=0; j<M1[i].size(); j++){ + multiply[i] += M1[i][j] * Vect[j]; + } + } + return multiply; +} + +//-------------------------------------------------------------- +template <typename T> +inline float getMeanVec(vector<T>& V){ + float tSum = 0.0f; + for (int n=0; n<V.size(); n++){ + tSum += V[n]; + } + return tSum / (float)V.size(); +} + +template <typename T> +inline vector<vector<float> > getRotationMatrix3d(T phi, T theta, T psi) +{ + vector< vector<float> > M; + initMat(M,3,3); + + M[0][0] = cos(theta)*cos(psi); + M[0][1] = -cos(phi)*sin(psi)+sin(phi)*sin(theta)*cos(psi); + M[0][2] = sin(phi)*sin(psi)+cos(phi)*sin(theta)*cos(psi); + + M[1][0] = cos(theta)*sin(psi); + M[1][1] = cos(phi)*cos(psi)+sin(phi)*sin(theta)*sin(psi); + M[1][2] = -sin(phi)*cos(psi)+cos(phi)*sin(theta)*sin(psi); + + M[2][0] = -sin(theta); + M[2][1] = sin(phi)*cos(theta); + M[2][2] = cos(phi)*cos(theta); + + return M; +} + +template <typename T> +float distance_weightedEuclidean(vector<T> x, vector<T> y, vector<T> w) +{ + int count = x.size(); + if (count <= 0) return 0; + float dist = 0.0; + for(int k = 0; k < count; k++) dist += w[k] * pow((x[k] - y[k]), 2); + return dist; +} + +////-------------------------------------------------------------- +//vector<vector<float> > getRotationMatrix3d(float phi, float theta, float psi) +//{ +// vector< vector<float> > M; +// initMat(M,3,3); +// +// M[0][0] = cos(theta)*cos(psi); +// M[0][1] = -cos(phi)*sin(psi)+sin(phi)*sin(theta)*cos(psi); +// M[0][2] = sin(phi)*sin(psi)+cos(phi)*sin(theta)*cos(psi); +// +// M[1][0] = cos(theta)*sin(psi); +// M[1][1] = cos(phi)*cos(psi)+sin(phi)*sin(theta)*sin(psi); +// M[1][2] = -sin(phi)*cos(psi)+cos(phi)*sin(theta)*sin(psi); +// +// M[2][0] = -sin(theta); +// M[2][1] = sin(phi)*cos(theta); +// M[2][2] = cos(phi)*cos(theta); +// +// return M; +//} + +//float distance_weightedEuclidean(vector<float> x, vector<float> y, vector<float> w) +//{ +// int count = x.size(); +// if (count <= 0) return 0; +// float dist = 0.0; +// for(int k = 0; k < count; k++) dist += w[k] * pow((x[k] - y[k]), 2); +// return dist; +//} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/GVF/LICENSE b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/LICENSE new file mode 100755 index 0000000000000000000000000000000000000000..6600f1c98d995efe077a253b2314cf26e633f32e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/GVF/LICENSE @@ -0,0 +1,165 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/json/json-forwards.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/json/json-forwards.h new file mode 100644 index 0000000000000000000000000000000000000000..65e8dfb295dc0356836484b59c56b9e3c010b741 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/json/json-forwards.h @@ -0,0 +1,324 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// 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_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 +#include <stddef.h> +#include <string> //typedef String +#include <stdint.h> //typedef int64_t, uint64_t + +/// 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 non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// 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 <cpptl/config.h> +#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) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#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) // MSVC +# if _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 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +#elif defined(_MSC_VER) && _MSC_VER > 1600 +# define JSONCPP_OVERRIDE override +#else +# define JSONCPP_OVERRIDE +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +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 int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // 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; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/json/json.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/json/json.h new file mode 100644 index 0000000000000000000000000000000000000000..de79502eebdf122bcbecaf0516b4de10409f44f6 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/json/json.h @@ -0,0 +1,2140 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// 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/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "1.7.7" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 7 +# define JSONCPP_VERSION_PATCH 7 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// 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 +#include <stddef.h> +#include <string> //typedef String +#include <stdint.h> //typedef int64_t, uint64_t + +/// 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 non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// 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 <cpptl/config.h> +#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) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#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) // MSVC +# if _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 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +#elif defined(_MSC_VER) && _MSC_VER > 1600 +# define JSONCPP_OVERRIDE override +#else +# define JSONCPP_OVERRIDE +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +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 int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // 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; + +} // 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_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // 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 <string> +#include <vector> +#include <exception> + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include <map> +#else +#include <cpptl/smallmap.h> +#endif +#ifdef JSON_USE_CPPTL +#include <cpptl/forwards.h> +#endif + +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() throw() JSONCPP_OVERRIDE; + char const* what() const throw() JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + +/** \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<const char *> EnumMemberNames; +// typedef CppTL::AnyEnumerator<const Value &> 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) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a <a HREF="http://www.json.org">JSON</a> 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 resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain 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. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector<JSONCPP_STRING> 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; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// 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; + +#if defined(JSON_HAS_INT64) + /// 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; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(CZString other); + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map<CZString, Value> ObjectValues; +#else + typedef CppTL::SmallMap<CZString, Value> ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#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); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \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. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value& operator=(Value other); + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + 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; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + 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 isInt64() const; + bool isUInt() const; + bool isUInt64() 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. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + 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. + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has 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. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \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 + /// \deprecated + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + Value removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) 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 + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + 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_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const JSONCPP_STRING& key); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + JSONCPP_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 JSON_API Path { +public: + Path(const JSONCPP_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<const PathArgument*> InArgs; + typedef std::vector<PathArgument> Args; + + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const JSONCPP_STRING& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + 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 other.computeDistance(*this); + } + + /// 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, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) 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: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +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(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +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(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#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 <deque> +#include <iosfwd> +#include <stack> +#include <string> +#include <istream> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \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 <a HREF="http://www.json.org">JSON</a> + * 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 <a HREF="http://www.json.org">JSON</a> + 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(JSONCPP_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.") + JSONCPP_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. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector<StructuredError> getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() 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_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque<ErrorInfo> Errors; + + 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 decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack<Value*> Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \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 errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, std::string* errs); + +/** \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<<() +*/ +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#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 <vector> +#include <string> +#include <ostream> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr<StreamWriter> const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr<Json::StreamWriter> writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "<anything>" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual JSONCPP_STRING write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> 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 + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API FastWriter : public Writer { + +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's Javascript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatiblityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> 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() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +public: // overridden from Writer + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> 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() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledStreamWriter { +public: + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> 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(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.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_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include <stdlib.h> +#include <sstream> + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/jsoncpp.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/jsoncpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ec7dded8d504e575660c506615efced908efeb4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/jsoncpp.cpp @@ -0,0 +1,5290 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// 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 +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" + +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// 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 + +#ifndef NO_LOCALE_SUPPORT +#include <clocale> +#endif + +/* 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 { +static char getDecimalPoint() { +#ifdef NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast<char>(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast<char>(0x80 | (0x3f & cp)); + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast<char>(0x80 | (0x3f & cp)); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast<char>(0x80 | (0x3f & cp)); + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +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*& current) { + *--current = 0; + do { + *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +static inline void fixNumericLocaleInput(char* begin, char* end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint != '\0' && decimalPoint != '.') { + while (begin < end) { + if (*begin == '.') { + *begin = decimalPoint; + } + ++begin; + } + } +} + +} // 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-2011 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 <json/assertions.h> +#include <json/reader.h> +#include <json/value.h> +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <utility> +#include <cstdio> +#include <cassert> +#include <cstring> +#include <istream> +#include <sstream> +#include <memory> +#include <set> +#include <limits> + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +static int const stackLimit_g = 1000; +static int stackDepth_g = 0; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<CharReader> CharReaderPtr; +#else +typedef std::auto_ptr<CharReader> CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +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() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool +Reader::parse(const std::string& document, Value& root, bool collectComments) { + JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); + std::swap(documentCopy, 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<char> begin(sin); + // std::istream_iterator<char> end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(sin, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), 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); + + stackDepth_g = 0; // Yes, this is bad coding, but options are limited. + 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() { + // This is a non-reentrant way to support a stackLimit. Terrible! + // But this deprecated class has a security problem: Bad input can + // cause a seg-fault. This seems like a fair, binary-compatible way + // to prevent the problem. + if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_g; + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_g; + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +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; +} + +static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast<size_t>(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +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; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); + } else { + break; + } + + 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) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *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) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // 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; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast<Value::UInt>(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast<size_t>(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& current, + 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& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int 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); + } + ret_unicode = static_cast<unsigned int>(unicode); + return true; +} + +bool +Reader::addError(const JSONCPP_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) { + size_t const errorCount = 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 JSONCPP_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; +} + +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +JSONCPP_STRING Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_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::vector<Reader::StructuredError> Reader::getStructuredErrors() const { + std::vector<Reader::StructuredError> allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { + return !errors_.size(); +} + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector<StructuredError> getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque<ErrorInfo> Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack<Value*> Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + int stackDepth_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), + stackDepth_(0), + features_(features), collectComments_() { +} + +bool OurReader::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); + + stackDepth_ = 0; + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + 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 OurReader::readValue() { + if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_; + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits<double>::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_; + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::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 '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else continue + 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': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + 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 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + 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 OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::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 OurReader::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 +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& tokenStart) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, 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 OurReader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *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 OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // 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; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast<Value::UInt>(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast<size_t>(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } else { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast<size_t>(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 OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + 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 OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int 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); + } + ret_unicode = static_cast<unsigned int>(unicode); + return true; +} + +bool +OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = 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 OurReader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::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; +} + +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_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::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { + std::vector<OurReader::StructuredError> allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { + return !errors_.size(); +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set<JSONCPP_STRING> valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) +{ + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_STRING doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// 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() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - 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 +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +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 2011 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 <json/assertions.h> +#include <json/value.h> +#include <json/writer.h> +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <math.h> +#include <sstream> +#include <utility> +#include <cstring> +#include <cassert> +#ifdef JSON_USE_CPPTL +#include <cpptl/conststring.h> +#endif +#include <cstddef> // size_t +#include <algorithm> // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +//const unsigned char& kNullRef = kNull[0]; +//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); +//const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() +{ + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but DO NOT +// use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + //return d >= static_cast<double>(min) && d <= static_cast<double>(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1)); +} + +template <typename T> static inline double integerToDouble(T value) { + return static_cast<double>(value); +} + +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** 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, + size_t length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast<size_t>(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast<char*>(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U; + char* newString = static_cast<char*>(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast<unsigned*>(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast<unsigned>(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast<unsigned const*>(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length==0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + free(value); +} +static inline void releaseStringValue(char* value, unsigned) { + free(value); +} +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(JSONCPP_STRING const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +LogicError::LogicError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) +{} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_, 0u); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = static_cast<unsigned>(other.cstr_ + ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(CZString other) { + swap(other); + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// 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 vtype) { + static char const empty[] = ""; + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast<char*>(static_cast<char const*>(empty)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); +} + +Value::Value(const JSONCPP_STRING& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast<char*>(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0), start_(other.start_), limit_(other.limit_) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + 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_, strlen(otherComment.comment_)); + } + } +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + delete[] comments_; + + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(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 & 0x1; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +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: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + 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_); + } + 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: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +JSONCPP_STRING Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return JSONCPP_STRING(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#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 intValue: + return static_cast<double>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<double>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast<float>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<float>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast<float>(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast<float>(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString() == "") || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// 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; + 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()); + } + 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_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + 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); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + 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, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(cend-key), 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, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullSingleton(); + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_STRING& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullSingleton(); + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const JSONCPP_STRING& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(JSONCPP_STRING const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(JSONCPP_STRING((*it).first.data(), + (*it).first.length())); + } + 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<const CZString &>() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type<const Value &>() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif +} + +bool Value::isDouble() const { return type_ == realValue || isIntegral(); } + +bool Value::isNumeric() const { return isIntegral() || isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { + StyledWriter writer; + return writer.write(*this); +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_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 JSONCPP_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 == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_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 JSONCPP_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... + return Value::null; + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + 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::nullSingleton()) + 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 2011 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 <json/writer.h> +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <iomanip> +#include <memory> +#include <sstream> +#include <utility> +#include <set> +#include <cassert> +#include <cstring> +#include <cstdio> + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include <float.h> +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) +#include <ieeefp.h> +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include <math.h> +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include <math.h> +#define isfinite finite +#endif +#endif +#else +#include <cmath> +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__BORLANDC__) +#include <float.h> +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<StreamWriter> StreamWriterPtr; +#else +typedef std::auto_ptr<StreamWriter> StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} +} + +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +JSONCPP_STRING valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + JSONCPP_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 </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if (isControlCharacter(*c)) { + JSONCPP_OSTRINGSTREAM oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++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 </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if ((isControlCharacter(*c)) || (*c == 0)) { + JSONCPP_OSTRINGSTREAM oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + 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: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex 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 JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_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: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 JSONCPP_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) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_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 JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + 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: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 JSONCPP_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 { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + 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) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +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; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set<JSONCPP_STRING> valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/libsvm/libsvm.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/libsvm/libsvm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77ea425b8b36460b69c43fc76dac3b99e527e557 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/libsvm/libsvm.cpp @@ -0,0 +1,3184 @@ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <float.h> +#include <string.h> +#include <stdarg.h> +#include <limits.h> +#include <locale.h> +#include "libsvm.h" + +namespace LIBSVM { + int libsvm_version = LIBSVM_VERSION; + typedef float Qfloat; + typedef signed char schar; +#ifndef min + template <class T> static inline T min(T x,T y) { return (x<y)?x:y; } +#endif +#ifndef max + template <class T> static inline T max(T x,T y) { return (x>y)?x:y; } +#endif + template <class T> static inline void swap(T& x, T& y) { T t=x; x=y; y=t; } + template <class S, class T> static inline void clone(T*& dst, S* src, int n) + { + dst = new T[n]; + memcpy((void *)dst,(void *)src,sizeof(T)*n); + } + static inline double powi(double base, int times) + { + double tmp = base, ret = 1.0; + + for(int t=times; t>0; t/=2) + { + if(t%2==1) ret*=tmp; + tmp = tmp * tmp; + } + return ret; + } +#define INF HUGE_VAL +#define TAU 1e-12 +#define Malloc(type,n) (type *)malloc((n)*sizeof(type)) + + static void print_string_stdout(const char *s) + { + fputs(s,stdout); + fflush(stdout); + } + static void (*svm_print_string) (const char *) = &print_string_stdout; +#if 1 + static void info(const char *fmt,...) + { + char buf[BUFSIZ]; + va_list ap; + va_start(ap,fmt); + vsprintf(buf,fmt,ap); + va_end(ap); + (*svm_print_string)(buf); + } +#else + static void info(const char *fmt,...) {} +#endif + + // + // Kernel Cache + // + // l is the number of total data items + // size is the cache size limit in bytes + // + class Cache + { + public: + Cache(int l,long int size); + ~Cache(); + + // request data [0,len) + // return some position p where [p,len) need to be filled + // (p >= len if nothing needs to be filled) + int get_data(const int index, Qfloat **data, int len); + void swap_index(int i, int j); + private: + int l; + long int size; + struct head_t + { + head_t *prev, *next; // a circular list + Qfloat *data; + int len; // data[0,len) is cached in this entry + }; + + head_t *head; + head_t lru_head; + void lru_delete(head_t *h); + void lru_insert(head_t *h); + }; + + Cache::Cache(int l_,long int size_):l(l_),size(size_) + { + head = (head_t *)calloc(l,sizeof(head_t)); // initialized to 0 + size /= sizeof(Qfloat); + size -= l * sizeof(head_t) / sizeof(Qfloat); + size = max(size, 2 * (long int) l); // cache must be large enough for two columns + lru_head.next = lru_head.prev = &lru_head; + } + + Cache::~Cache() + { + for(head_t *h = lru_head.next; h != &lru_head; h=h->next) + free(h->data); + free(head); + } + + void Cache::lru_delete(head_t *h) + { + // delete from current location + h->prev->next = h->next; + h->next->prev = h->prev; + } + + void Cache::lru_insert(head_t *h) + { + // insert to last position + h->next = &lru_head; + h->prev = lru_head.prev; + h->prev->next = h; + h->next->prev = h; + } + + int Cache::get_data(const int index, Qfloat **data, int len) + { + head_t *h = &head[index]; + if(h->len) lru_delete(h); + int more = len - h->len; + + if(more > 0) + { + // free old space + while(size < more) + { + head_t *old = lru_head.next; + lru_delete(old); + free(old->data); + size += old->len; + old->data = 0; + old->len = 0; + } + + // allocate new space + h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len); + size -= more; + swap(h->len,len); + } + + lru_insert(h); + *data = h->data; + return len; + } + + void Cache::swap_index(int i, int j) + { + if(i==j) return; + + if(head[i].len) lru_delete(&head[i]); + if(head[j].len) lru_delete(&head[j]); + swap(head[i].data,head[j].data); + swap(head[i].len,head[j].len); + if(head[i].len) lru_insert(&head[i]); + if(head[j].len) lru_insert(&head[j]); + + if(i>j) swap(i,j); + for(head_t *h = lru_head.next; h!=&lru_head; h=h->next) + { + if(h->len > i) + { + if(h->len > j) + swap(h->data[i],h->data[j]); + else + { + // give up + lru_delete(h); + free(h->data); + size += h->len; + h->data = 0; + h->len = 0; + } + } + } + } + + // + // Kernel evaluation + // + // the static method k_function is for doing single kernel evaluation + // the constructor of Kernel prepares to calculate the l*l kernel matrix + // the member function get_Q is for getting one column from the Q Matrix + // + class QMatrix { + public: + virtual Qfloat *get_Q(int column, int len) const = 0; + virtual double *get_QD() const = 0; + virtual void swap_index(int i, int j) const = 0; + virtual ~QMatrix() {} + }; + + class Kernel: public QMatrix { + public: + Kernel(int l, svm_node * const * x, const svm_parameter& param); + virtual ~Kernel(); + + static double k_function(const svm_node *x, const svm_node *y, + const svm_parameter& param); + virtual Qfloat *get_Q(int column, int len) const = 0; + virtual double *get_QD() const = 0; + virtual void swap_index(int i, int j) const // no so const... + { + swap(x[i],x[j]); + if(x_square) swap(x_square[i],x_square[j]); + } + protected: + + double (Kernel::*kernel_function)(int i, int j) const; + + private: + const svm_node **x; + double *x_square; + + // svm_parameter + const int kernel_type; + const int degree; + const double gamma; + const double coef0; + + static double dot(const svm_node *px, const svm_node *py); + double kernel_linear(int i, int j) const + { + return dot(x[i],x[j]); + } + double kernel_poly(int i, int j) const + { + return powi(gamma*dot(x[i],x[j])+coef0,degree); + } + double kernel_rbf(int i, int j) const + { + return exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j]))); + } + double kernel_sigmoid(int i, int j) const + { + return tanh(gamma*dot(x[i],x[j])+coef0); + } + double kernel_precomputed(int i, int j) const + { + return x[i][(int)(x[j][0].value)].value; + } + }; + + Kernel::Kernel(int l, svm_node * const * x_, const svm_parameter& param) + :kernel_type(param.kernel_type), degree(param.degree), + gamma(param.gamma), coef0(param.coef0) + { + switch(kernel_type) + { + case LINEAR: + kernel_function = &Kernel::kernel_linear; + break; + case POLY: + kernel_function = &Kernel::kernel_poly; + break; + case RBF: + kernel_function = &Kernel::kernel_rbf; + break; + case SIGMOID: + kernel_function = &Kernel::kernel_sigmoid; + break; + case PRECOMPUTED: + kernel_function = &Kernel::kernel_precomputed; + break; + } + + clone(x,x_,l); + + if(kernel_type == RBF) + { + x_square = new double[l]; + for(int i=0;i<l;i++) + x_square[i] = dot(x[i],x[i]); + } + else + x_square = 0; + } + + Kernel::~Kernel() + { + delete[] x; + delete[] x_square; + } + + double Kernel::dot(const svm_node *px, const svm_node *py) + { + double sum = 0; + while(px->index != -1 && py->index != -1) + { + if(px->index == py->index) + { + sum += px->value * py->value; + ++px; + ++py; + } + else + { + if(px->index > py->index) + ++py; + else + ++px; + } + } + return sum; + } + + double Kernel::k_function(const svm_node *x, const svm_node *y, + const svm_parameter& param) + { + switch(param.kernel_type) + { + case LINEAR: + return dot(x,y); + case POLY: + return powi(param.gamma*dot(x,y)+param.coef0,param.degree); + case RBF: + { + double sum = 0; + while(x->index != -1 && y->index !=-1) + { + if(x->index == y->index) + { + double d = x->value - y->value; + sum += d*d; + ++x; + ++y; + } + else + { + if(x->index > y->index) + { + sum += y->value * y->value; + ++y; + } + else + { + sum += x->value * x->value; + ++x; + } + } + } + + while(x->index != -1) + { + sum += x->value * x->value; + ++x; + } + + while(y->index != -1) + { + sum += y->value * y->value; + ++y; + } + + return exp(-param.gamma*sum); + } + case SIGMOID: + return tanh(param.gamma*dot(x,y)+param.coef0); + case PRECOMPUTED: //x: test (validation), y: SV + return x[(int)(y->value)].value; + default: + return 0; // Unreachable + } + } + + // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918 + // Solves: + // + // min 0.5(\alpha^T Q \alpha) + p^T \alpha + // + // y^T \alpha = \delta + // y_i = +1 or -1 + // 0 <= alpha_i <= Cp for y_i = 1 + // 0 <= alpha_i <= Cn for y_i = -1 + // + // Given: + // + // Q, p, y, Cp, Cn, and an initial feasible point \alpha + // l is the size of vectors and matrices + // eps is the stopping tolerance + // + // solution will be put in \alpha, objective value will be put in obj + // + class Solver { + public: + Solver() {}; + virtual ~Solver() {}; + + struct SolutionInfo { + double obj; + double rho; + double upper_bound_p; + double upper_bound_n; + double r; // for Solver_NU + }; + + void Solve(int l, const QMatrix& Q, const double *p_, const schar *y_, + double *alpha_, double Cp, double Cn, double eps, + SolutionInfo* si, int shrinking); + protected: + int active_size; + schar *y; + double *G; // gradient of objective function + enum { LOWER_BOUND, UPPER_BOUND, FREE }; + char *alpha_status; // LOWER_BOUND, UPPER_BOUND, FREE + double *alpha; + const QMatrix *Q; + const double *QD; + double eps; + double Cp,Cn; + double *p; + int *active_set; + double *G_bar; // gradient, if we treat free variables as 0 + int l; + bool unshrink; // XXX + + double get_C(int i) + { + return (y[i] > 0)? Cp : Cn; + } + void update_alpha_status(int i) + { + if(alpha[i] >= get_C(i)) + alpha_status[i] = UPPER_BOUND; + else if(alpha[i] <= 0) + alpha_status[i] = LOWER_BOUND; + else alpha_status[i] = FREE; + } + bool is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; } + bool is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; } + bool is_free(int i) { return alpha_status[i] == FREE; } + void swap_index(int i, int j); + void reconstruct_gradient(); + virtual int select_working_set(int &i, int &j); + virtual double calculate_rho(); + virtual void do_shrinking(); + private: + bool be_shrunk(int i, double Gmax1, double Gmax2); + }; + + void Solver::swap_index(int i, int j) + { + Q->swap_index(i,j); + swap(y[i],y[j]); + swap(G[i],G[j]); + swap(alpha_status[i],alpha_status[j]); + swap(alpha[i],alpha[j]); + swap(p[i],p[j]); + swap(active_set[i],active_set[j]); + swap(G_bar[i],G_bar[j]); + } + + void Solver::reconstruct_gradient() + { + // reconstruct inactive elements of G from G_bar and free variables + + if(active_size == l) return; + + int i,j; + int nr_free = 0; + + for(j=active_size;j<l;j++) + G[j] = G_bar[j] + p[j]; + + for(j=0;j<active_size;j++) + if(is_free(j)) + nr_free++; + + if(2*nr_free < active_size) + info("\nWARNING: using -h 0 may be faster\n"); + + if (nr_free*l > 2*active_size*(l-active_size)) + { + for(i=active_size;i<l;i++) + { + const Qfloat *Q_i = Q->get_Q(i,active_size); + for(j=0;j<active_size;j++) + if(is_free(j)) + G[i] += alpha[j] * Q_i[j]; + } + } + else + { + for(i=0;i<active_size;i++) + if(is_free(i)) + { + const Qfloat *Q_i = Q->get_Q(i,l); + double alpha_i = alpha[i]; + for(j=active_size;j<l;j++) + G[j] += alpha_i * Q_i[j]; + } + } + } + + void Solver::Solve(int l, const QMatrix& Q, const double *p_, const schar *y_, + double *alpha_, double Cp, double Cn, double eps, + SolutionInfo* si, int shrinking) + { + this->l = l; + this->Q = &Q; + QD=Q.get_QD(); + clone(p, p_,l); + clone(y, y_,l); + clone(alpha,alpha_,l); + this->Cp = Cp; + this->Cn = Cn; + this->eps = eps; + unshrink = false; + + // initialize alpha_status + { + alpha_status = new char[l]; + for(int i=0;i<l;i++) + update_alpha_status(i); + } + + // initialize active set (for shrinking) + { + active_set = new int[l]; + for(int i=0;i<l;i++) + active_set[i] = i; + active_size = l; + } + + // initialize gradient + { + G = new double[l]; + G_bar = new double[l]; + int i; + for(i=0;i<l;i++) + { + G[i] = p[i]; + G_bar[i] = 0; + } + for(i=0;i<l;i++) + if(!is_lower_bound(i)) + { + const Qfloat *Q_i = Q.get_Q(i,l); + double alpha_i = alpha[i]; + int j; + for(j=0;j<l;j++) + G[j] += alpha_i*Q_i[j]; + if(is_upper_bound(i)) + for(j=0;j<l;j++) + G_bar[j] += get_C(i) * Q_i[j]; + } + } + + // optimization step + + int iter = 0; + int max_iter = max(10000000, l>INT_MAX/100 ? INT_MAX : 100*l); + int counter = min(l,1000)+1; + + while(iter < max_iter) + { + // show progress and do shrinking + + if(--counter == 0) + { + counter = min(l,1000); + if(shrinking) do_shrinking(); + info("."); + } + + int i,j; + if(select_working_set(i,j)!=0) + { + // reconstruct the whole gradient + reconstruct_gradient(); + // reset active set size and check + active_size = l; + info("*"); + if(select_working_set(i,j)!=0) + break; + else + counter = 1; // do shrinking next iteration + } + + ++iter; + + // update alpha[i] and alpha[j], handle bounds carefully + + const Qfloat *Q_i = Q.get_Q(i,active_size); + const Qfloat *Q_j = Q.get_Q(j,active_size); + + double C_i = get_C(i); + double C_j = get_C(j); + + double old_alpha_i = alpha[i]; + double old_alpha_j = alpha[j]; + + if(y[i]!=y[j]) + { + double quad_coef = QD[i]+QD[j]+2*Q_i[j]; + if (quad_coef <= 0) + quad_coef = TAU; + double delta = (-G[i]-G[j])/quad_coef; + double diff = alpha[i] - alpha[j]; + alpha[i] += delta; + alpha[j] += delta; + + if(diff > 0) + { + if(alpha[j] < 0) + { + alpha[j] = 0; + alpha[i] = diff; + } + } + else + { + if(alpha[i] < 0) + { + alpha[i] = 0; + alpha[j] = -diff; + } + } + if(diff > C_i - C_j) + { + if(alpha[i] > C_i) + { + alpha[i] = C_i; + alpha[j] = C_i - diff; + } + } + else + { + if(alpha[j] > C_j) + { + alpha[j] = C_j; + alpha[i] = C_j + diff; + } + } + } + else + { + double quad_coef = QD[i]+QD[j]-2*Q_i[j]; + if (quad_coef <= 0) + quad_coef = TAU; + double delta = (G[i]-G[j])/quad_coef; + double sum = alpha[i] + alpha[j]; + alpha[i] -= delta; + alpha[j] += delta; + + if(sum > C_i) + { + if(alpha[i] > C_i) + { + alpha[i] = C_i; + alpha[j] = sum - C_i; + } + } + else + { + if(alpha[j] < 0) + { + alpha[j] = 0; + alpha[i] = sum; + } + } + if(sum > C_j) + { + if(alpha[j] > C_j) + { + alpha[j] = C_j; + alpha[i] = sum - C_j; + } + } + else + { + if(alpha[i] < 0) + { + alpha[i] = 0; + alpha[j] = sum; + } + } + } + + // update G + + double delta_alpha_i = alpha[i] - old_alpha_i; + double delta_alpha_j = alpha[j] - old_alpha_j; + + for(int k=0;k<active_size;k++) + { + G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j; + } + + // update alpha_status and G_bar + + { + bool ui = is_upper_bound(i); + bool uj = is_upper_bound(j); + update_alpha_status(i); + update_alpha_status(j); + int k; + if(ui != is_upper_bound(i)) + { + Q_i = Q.get_Q(i,l); + if(ui) + for(k=0;k<l;k++) + G_bar[k] -= C_i * Q_i[k]; + else + for(k=0;k<l;k++) + G_bar[k] += C_i * Q_i[k]; + } + + if(uj != is_upper_bound(j)) + { + Q_j = Q.get_Q(j,l); + if(uj) + for(k=0;k<l;k++) + G_bar[k] -= C_j * Q_j[k]; + else + for(k=0;k<l;k++) + G_bar[k] += C_j * Q_j[k]; + } + } + } + + if(iter >= max_iter) + { + if(active_size < l) + { + // reconstruct the whole gradient to calculate objective value + reconstruct_gradient(); + active_size = l; + info("*"); + } + fprintf(stderr,"\nWARNING: reaching max number of iterations\n"); + } + + // calculate rho + + si->rho = calculate_rho(); + + // calculate objective value + { + double v = 0; + int i; + for(i=0;i<l;i++) + v += alpha[i] * (G[i] + p[i]); + + si->obj = v/2; + } + + // put back the solution + { + for(int i=0;i<l;i++) + alpha_[active_set[i]] = alpha[i]; + } + + // juggle everything back + /*{ + for(int i=0;i<l;i++) + while(active_set[i] != i) + swap_index(i,active_set[i]); + // or Q.swap_index(i,active_set[i]); + }*/ + + si->upper_bound_p = Cp; + si->upper_bound_n = Cn; + + info("\noptimization finished, #iter = %d\n",iter); + + delete[] p; + delete[] y; + delete[] alpha; + delete[] alpha_status; + delete[] active_set; + delete[] G; + delete[] G_bar; + } + + // return 1 if already optimal, return 0 otherwise + int Solver::select_working_set(int &out_i, int &out_j) + { + // return i,j such that + // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) + // j: minimizes the decrease of obj value + // (if quadratic coefficeint <= 0, replace it with tau) + // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) + + double Gmax = -INF; + double Gmax2 = -INF; + int Gmax_idx = -1; + int Gmin_idx = -1; + double obj_diff_min = INF; + + for(int t=0;t<active_size;t++) + if(y[t]==+1) + { + if(!is_upper_bound(t)) + if(-G[t] >= Gmax) + { + Gmax = -G[t]; + Gmax_idx = t; + } + } + else + { + if(!is_lower_bound(t)) + if(G[t] >= Gmax) + { + Gmax = G[t]; + Gmax_idx = t; + } + } + + int i = Gmax_idx; + const Qfloat *Q_i = NULL; + if(i != -1) // NULL Q_i not accessed: Gmax=-INF if i=-1 + Q_i = Q->get_Q(i,active_size); + + for(int j=0;j<active_size;j++) + { + if(y[j]==+1) + { + if (!is_lower_bound(j)) + { + double grad_diff=Gmax+G[j]; + if (G[j] >= Gmax2) + Gmax2 = G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + else + { + if (!is_upper_bound(j)) + { + double grad_diff= Gmax-G[j]; + if (-G[j] >= Gmax2) + Gmax2 = -G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + } + + if(Gmax+Gmax2 < eps || Gmin_idx == -1) + return 1; + + out_i = Gmax_idx; + out_j = Gmin_idx; + return 0; + } + + bool Solver::be_shrunk(int i, double Gmax1, double Gmax2) + { + if(is_upper_bound(i)) + { + if(y[i]==+1) + return(-G[i] > Gmax1); + else + return(-G[i] > Gmax2); + } + else if(is_lower_bound(i)) + { + if(y[i]==+1) + return(G[i] > Gmax2); + else + return(G[i] > Gmax1); + } + else + return(false); + } + + void Solver::do_shrinking() + { + int i; + double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) } + double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) } + + // find maximal violating pair first + for(i=0;i<active_size;i++) + { + if(y[i]==+1) + { + if(!is_upper_bound(i)) + { + if(-G[i] >= Gmax1) + Gmax1 = -G[i]; + } + if(!is_lower_bound(i)) + { + if(G[i] >= Gmax2) + Gmax2 = G[i]; + } + } + else + { + if(!is_upper_bound(i)) + { + if(-G[i] >= Gmax2) + Gmax2 = -G[i]; + } + if(!is_lower_bound(i)) + { + if(G[i] >= Gmax1) + Gmax1 = G[i]; + } + } + } + + if(unshrink == false && Gmax1 + Gmax2 <= eps*10) + { + unshrink = true; + reconstruct_gradient(); + active_size = l; + info("*"); + } + + for(i=0;i<active_size;i++) + if (be_shrunk(i, Gmax1, Gmax2)) + { + active_size--; + while (active_size > i) + { + if (!be_shrunk(active_size, Gmax1, Gmax2)) + { + swap_index(i,active_size); + break; + } + active_size--; + } + } + } + + double Solver::calculate_rho() + { + double r; + int nr_free = 0; + double ub = INF, lb = -INF, sum_free = 0; + for(int i=0;i<active_size;i++) + { + double yG = y[i]*G[i]; + + if(is_upper_bound(i)) + { + if(y[i]==-1) + ub = min(ub,yG); + else + lb = max(lb,yG); + } + else if(is_lower_bound(i)) + { + if(y[i]==+1) + ub = min(ub,yG); + else + lb = max(lb,yG); + } + else + { + ++nr_free; + sum_free += yG; + } + } + + if(nr_free>0) + r = sum_free/nr_free; + else + r = (ub+lb)/2; + + return r; + } + + // + // Solver for nu-svm classification and regression + // + // additional constraint: e^T \alpha = constant + // + class Solver_NU: public Solver + { + public: + Solver_NU() {} + void Solve(int l, const QMatrix& Q, const double *p, const schar *y, + double *alpha, double Cp, double Cn, double eps, + SolutionInfo* si, int shrinking) + { + this->si = si; + Solver::Solve(l,Q,p,y,alpha,Cp,Cn,eps,si,shrinking); + } + private: + SolutionInfo *si; + int select_working_set(int &i, int &j); + double calculate_rho(); + bool be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4); + void do_shrinking(); + }; + + // return 1 if already optimal, return 0 otherwise + int Solver_NU::select_working_set(int &out_i, int &out_j) + { + // return i,j such that y_i = y_j and + // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) + // j: minimizes the decrease of obj value + // (if quadratic coefficeint <= 0, replace it with tau) + // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) + + double Gmaxp = -INF; + double Gmaxp2 = -INF; + int Gmaxp_idx = -1; + + double Gmaxn = -INF; + double Gmaxn2 = -INF; + int Gmaxn_idx = -1; + + int Gmin_idx = -1; + double obj_diff_min = INF; + + for(int t=0;t<active_size;t++) + if(y[t]==+1) + { + if(!is_upper_bound(t)) + if(-G[t] >= Gmaxp) + { + Gmaxp = -G[t]; + Gmaxp_idx = t; + } + } + else + { + if(!is_lower_bound(t)) + if(G[t] >= Gmaxn) + { + Gmaxn = G[t]; + Gmaxn_idx = t; + } + } + + int ip = Gmaxp_idx; + int in = Gmaxn_idx; + const Qfloat *Q_ip = NULL; + const Qfloat *Q_in = NULL; + if(ip != -1) // NULL Q_ip not accessed: Gmaxp=-INF if ip=-1 + Q_ip = Q->get_Q(ip,active_size); + if(in != -1) + Q_in = Q->get_Q(in,active_size); + + for(int j=0;j<active_size;j++) + { + if(y[j]==+1) + { + if (!is_lower_bound(j)) + { + double grad_diff=Gmaxp+G[j]; + if (G[j] >= Gmaxp2) + Gmaxp2 = G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[ip]+QD[j]-2*Q_ip[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + else + { + if (!is_upper_bound(j)) + { + double grad_diff=Gmaxn-G[j]; + if (-G[j] >= Gmaxn2) + Gmaxn2 = -G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[in]+QD[j]-2*Q_in[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + } + + if(max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps || Gmin_idx == -1) + return 1; + + if (y[Gmin_idx] == +1) + out_i = Gmaxp_idx; + else + out_i = Gmaxn_idx; + out_j = Gmin_idx; + + return 0; + } + + bool Solver_NU::be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4) + { + if(is_upper_bound(i)) + { + if(y[i]==+1) + return(-G[i] > Gmax1); + else + return(-G[i] > Gmax4); + } + else if(is_lower_bound(i)) + { + if(y[i]==+1) + return(G[i] > Gmax2); + else + return(G[i] > Gmax3); + } + else + return(false); + } + + void Solver_NU::do_shrinking() + { + double Gmax1 = -INF; // max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) } + double Gmax2 = -INF; // max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) } + double Gmax3 = -INF; // max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) } + double Gmax4 = -INF; // max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) } + + // find maximal violating pair first + int i; + for(i=0;i<active_size;i++) + { + if(!is_upper_bound(i)) + { + if(y[i]==+1) + { + if(-G[i] > Gmax1) Gmax1 = -G[i]; + } + else if(-G[i] > Gmax4) Gmax4 = -G[i]; + } + if(!is_lower_bound(i)) + { + if(y[i]==+1) + { + if(G[i] > Gmax2) Gmax2 = G[i]; + } + else if(G[i] > Gmax3) Gmax3 = G[i]; + } + } + + if(unshrink == false && max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10) + { + unshrink = true; + reconstruct_gradient(); + active_size = l; + } + + for(i=0;i<active_size;i++) + if (be_shrunk(i, Gmax1, Gmax2, Gmax3, Gmax4)) + { + active_size--; + while (active_size > i) + { + if (!be_shrunk(active_size, Gmax1, Gmax2, Gmax3, Gmax4)) + { + swap_index(i,active_size); + break; + } + active_size--; + } + } + } + + double Solver_NU::calculate_rho() + { + int nr_free1 = 0,nr_free2 = 0; + double ub1 = INF, ub2 = INF; + double lb1 = -INF, lb2 = -INF; + double sum_free1 = 0, sum_free2 = 0; + + for(int i=0;i<active_size;i++) + { + if(y[i]==+1) + { + if(is_upper_bound(i)) + lb1 = max(lb1,G[i]); + else if(is_lower_bound(i)) + ub1 = min(ub1,G[i]); + else + { + ++nr_free1; + sum_free1 += G[i]; + } + } + else + { + if(is_upper_bound(i)) + lb2 = max(lb2,G[i]); + else if(is_lower_bound(i)) + ub2 = min(ub2,G[i]); + else + { + ++nr_free2; + sum_free2 += G[i]; + } + } + } + + double r1,r2; + if(nr_free1 > 0) + r1 = sum_free1/nr_free1; + else + r1 = (ub1+lb1)/2; + + if(nr_free2 > 0) + r2 = sum_free2/nr_free2; + else + r2 = (ub2+lb2)/2; + + si->r = (r1+r2)/2; + return (r1-r2)/2; + } + + // + // Q matrices for various formulations + // + class SVC_Q: public Kernel + { + public: + SVC_Q(const svm_problem& prob, const svm_parameter& param, const schar *y_) + :Kernel(prob.l, prob.x, param) + { + clone(y,y_,prob.l); + cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20))); + QD = new double[prob.l]; + for(int i=0;i<prob.l;i++) + QD[i] = (this->*kernel_function)(i,i); + } + + Qfloat *get_Q(int i, int len) const + { + Qfloat *data; + int start, j; + if((start = cache->get_data(i,&data,len)) < len) + { + for(j=start;j<len;j++) + data[j] = (Qfloat)(y[i]*y[j]*(this->*kernel_function)(i,j)); + } + return data; + } + + double *get_QD() const + { + return QD; + } + + void swap_index(int i, int j) const + { + cache->swap_index(i,j); + Kernel::swap_index(i,j); + swap(y[i],y[j]); + swap(QD[i],QD[j]); + } + + ~SVC_Q() + { + delete[] y; + delete cache; + delete[] QD; + } + private: + schar *y; + Cache *cache; + double *QD; + }; + + class ONE_CLASS_Q: public Kernel + { + public: + ONE_CLASS_Q(const svm_problem& prob, const svm_parameter& param) + :Kernel(prob.l, prob.x, param) + { + cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20))); + QD = new double[prob.l]; + for(int i=0;i<prob.l;i++) + QD[i] = (this->*kernel_function)(i,i); + } + + Qfloat *get_Q(int i, int len) const + { + Qfloat *data; + int start, j; + if((start = cache->get_data(i,&data,len)) < len) + { + for(j=start;j<len;j++) + data[j] = (Qfloat)(this->*kernel_function)(i,j); + } + return data; + } + + double *get_QD() const + { + return QD; + } + + void swap_index(int i, int j) const + { + cache->swap_index(i,j); + Kernel::swap_index(i,j); + swap(QD[i],QD[j]); + } + + ~ONE_CLASS_Q() + { + delete cache; + delete[] QD; + } + private: + Cache *cache; + double *QD; + }; + + class SVR_Q: public Kernel + { + public: + SVR_Q(const svm_problem& prob, const svm_parameter& param) + :Kernel(prob.l, prob.x, param) + { + l = prob.l; + cache = new Cache(l,(long int)(param.cache_size*(1<<20))); + QD = new double[2*l]; + sign = new schar[2*l]; + index = new int[2*l]; + for(int k=0;k<l;k++) + { + sign[k] = 1; + sign[k+l] = -1; + index[k] = k; + index[k+l] = k; + QD[k] = (this->*kernel_function)(k,k); + QD[k+l] = QD[k]; + } + buffer[0] = new Qfloat[2*l]; + buffer[1] = new Qfloat[2*l]; + next_buffer = 0; + } + + void swap_index(int i, int j) const + { + swap(sign[i],sign[j]); + swap(index[i],index[j]); + swap(QD[i],QD[j]); + } + + Qfloat *get_Q(int i, int len) const + { + Qfloat *data; + int j, real_i = index[i]; + if(cache->get_data(real_i,&data,l) < l) + { + for(j=0;j<l;j++) + data[j] = (Qfloat)(this->*kernel_function)(real_i,j); + } + + // reorder and copy + Qfloat *buf = buffer[next_buffer]; + next_buffer = 1 - next_buffer; + schar si = sign[i]; + for(j=0;j<len;j++) + buf[j] = (Qfloat) si * (Qfloat) sign[j] * data[index[j]]; + return buf; + } + + double *get_QD() const + { + return QD; + } + + ~SVR_Q() + { + delete cache; + delete[] sign; + delete[] index; + delete[] buffer[0]; + delete[] buffer[1]; + delete[] QD; + } + private: + int l; + Cache *cache; + schar *sign; + int *index; + mutable int next_buffer; + Qfloat *buffer[2]; + double *QD; + }; + + // + // construct and solve various formulations + // + static void solve_c_svc( + const svm_problem *prob, const svm_parameter* param, + double *alpha, Solver::SolutionInfo* si, double Cp, double Cn) + { + int l = prob->l; + double *minus_ones = new double[l]; + schar *y = new schar[l]; + + int i; + + for(i=0;i<l;i++) + { + alpha[i] = 0; + minus_ones[i] = -1; + if(prob->y[i] > 0) y[i] = +1; else y[i] = -1; + } + + Solver s; + s.Solve(l, SVC_Q(*prob,*param,y), minus_ones, y, + alpha, Cp, Cn, param->eps, si, param->shrinking); + + double sum_alpha=0; + for(i=0;i<l;i++) + sum_alpha += alpha[i]; + + if (Cp==Cn) + info("nu = %f\n", sum_alpha/(Cp*prob->l)); + + for(i=0;i<l;i++) + alpha[i] *= y[i]; + + delete[] minus_ones; + delete[] y; + } + + static void solve_nu_svc( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int i; + int l = prob->l; + double nu = param->nu; + + schar *y = new schar[l]; + + for(i=0;i<l;i++) + if(prob->y[i]>0) + y[i] = +1; + else + y[i] = -1; + + double sum_pos = nu*l/2; + double sum_neg = nu*l/2; + + for(i=0;i<l;i++) + if(y[i] == +1) + { + alpha[i] = min(1.0,sum_pos); + sum_pos -= alpha[i]; + } + else + { + alpha[i] = min(1.0,sum_neg); + sum_neg -= alpha[i]; + } + + double *zeros = new double[l]; + + for(i=0;i<l;i++) + zeros[i] = 0; + + Solver_NU s; + s.Solve(l, SVC_Q(*prob,*param,y), zeros, y, + alpha, 1.0, 1.0, param->eps, si, param->shrinking); + double r = si->r; + + info("C = %f\n",1/r); + + for(i=0;i<l;i++) + alpha[i] *= y[i]/r; + + si->rho /= r; + si->obj /= (r*r); + si->upper_bound_p = 1/r; + si->upper_bound_n = 1/r; + + delete[] y; + delete[] zeros; + } + + static void solve_one_class( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int l = prob->l; + double *zeros = new double[l]; + schar *ones = new schar[l]; + int i; + + int n = (int)(param->nu*prob->l); // # of alpha's at upper bound + + for(i=0;i<n;i++) + alpha[i] = 1; + if(n<prob->l) + alpha[n] = param->nu * prob->l - n; + for(i=n+1;i<l;i++) + alpha[i] = 0; + + for(i=0;i<l;i++) + { + zeros[i] = 0; + ones[i] = 1; + } + + Solver s; + s.Solve(l, ONE_CLASS_Q(*prob,*param), zeros, ones, + alpha, 1.0, 1.0, param->eps, si, param->shrinking); + + delete[] zeros; + delete[] ones; + } + + static void solve_epsilon_svr( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int l = prob->l; + double *alpha2 = new double[2*l]; + double *linear_term = new double[2*l]; + schar *y = new schar[2*l]; + int i; + + for(i=0;i<l;i++) + { + alpha2[i] = 0; + linear_term[i] = param->p - prob->y[i]; + y[i] = 1; + + alpha2[i+l] = 0; + linear_term[i+l] = param->p + prob->y[i]; + y[i+l] = -1; + } + + Solver s; + s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y, + alpha2, param->C, param->C, param->eps, si, param->shrinking); + + double sum_alpha = 0; + for(i=0;i<l;i++) + { + alpha[i] = alpha2[i] - alpha2[i+l]; + sum_alpha += fabs(alpha[i]); + } + info("nu = %f\n",sum_alpha/(param->C*l)); + + delete[] alpha2; + delete[] linear_term; + delete[] y; + } + + static void solve_nu_svr( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int l = prob->l; + double C = param->C; + double *alpha2 = new double[2*l]; + double *linear_term = new double[2*l]; + schar *y = new schar[2*l]; + int i; + + double sum = C * param->nu * l / 2; + for(i=0;i<l;i++) + { + alpha2[i] = alpha2[i+l] = min(sum,C); + sum -= alpha2[i]; + + linear_term[i] = - prob->y[i]; + y[i] = 1; + + linear_term[i+l] = prob->y[i]; + y[i+l] = -1; + } + + Solver_NU s; + s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y, + alpha2, C, C, param->eps, si, param->shrinking); + + info("epsilon = %f\n",-si->r); + + for(i=0;i<l;i++) + alpha[i] = alpha2[i] - alpha2[i+l]; + + delete[] alpha2; + delete[] linear_term; + delete[] y; + } + + // + // decision_function + // + struct decision_function + { + double *alpha; + double rho; + }; + + static decision_function svm_train_one( + const svm_problem *prob, const svm_parameter *param, + double Cp, double Cn) + { + double *alpha = Malloc(double,prob->l); + Solver::SolutionInfo si; + switch(param->svm_type) + { + case C_SVC: + solve_c_svc(prob,param,alpha,&si,Cp,Cn); + break; + case NU_SVC: + solve_nu_svc(prob,param,alpha,&si); + break; + case ONE_CLASS: + solve_one_class(prob,param,alpha,&si); + break; + case EPSILON_SVR: + solve_epsilon_svr(prob,param,alpha,&si); + break; + case NU_SVR: + solve_nu_svr(prob,param,alpha,&si); + break; + } + + info("obj = %f, rho = %f\n",si.obj,si.rho); + + // output SVs + + int nSV = 0; + int nBSV = 0; + for(int i=0;i<prob->l;i++) + { + if(fabs(alpha[i]) > 0) + { + ++nSV; + if(prob->y[i] > 0) + { + if(fabs(alpha[i]) >= si.upper_bound_p) + ++nBSV; + } + else + { + if(fabs(alpha[i]) >= si.upper_bound_n) + ++nBSV; + } + } + } + + info("nSV = %d, nBSV = %d\n",nSV,nBSV); + + decision_function f; + f.alpha = alpha; + f.rho = si.rho; + return f; + } + + // Platt's binary SVM Probablistic Output: an improvement from Lin et al. + static void sigmoid_train( + int l, const double *dec_values, const double *labels, + double& A, double& B) + { + double prior1=0, prior0 = 0; + int i; + + for (i=0;i<l;i++) + if (labels[i] > 0) prior1+=1; + else prior0+=1; + + int max_iter=100; // Maximal number of iterations + double min_step=1e-10; // Minimal step taken in line search + double sigma=1e-12; // For numerically strict PD of Hessian + double eps=1e-5; + double hiTarget=(prior1+1.0)/(prior1+2.0); + double loTarget=1/(prior0+2.0); + double *t=Malloc(double,l); + double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize; + double newA,newB,newf,d1,d2; + int iter; + + // Initial Point and Initial Fun Value + A=0.0; B=log((prior0+1.0)/(prior1+1.0)); + double fval = 0.0; + + for (i=0;i<l;i++) + { + if (labels[i]>0) t[i]=hiTarget; + else t[i]=loTarget; + fApB = dec_values[i]*A+B; + if (fApB>=0) + fval += t[i]*fApB + log(1+exp(-fApB)); + else + fval += (t[i] - 1)*fApB +log(1+exp(fApB)); + } + for (iter=0;iter<max_iter;iter++) + { + // Update Gradient and Hessian (use H' = H + sigma I) + h11=sigma; // numerically ensures strict PD + h22=sigma; + h21=0.0;g1=0.0;g2=0.0; + for (i=0;i<l;i++) + { + fApB = dec_values[i]*A+B; + if (fApB >= 0) + { + p=exp(-fApB)/(1.0+exp(-fApB)); + q=1.0/(1.0+exp(-fApB)); + } + else + { + p=1.0/(1.0+exp(fApB)); + q=exp(fApB)/(1.0+exp(fApB)); + } + d2=p*q; + h11+=dec_values[i]*dec_values[i]*d2; + h22+=d2; + h21+=dec_values[i]*d2; + d1=t[i]-p; + g1+=dec_values[i]*d1; + g2+=d1; + } + + // Stopping Criteria + if (fabs(g1)<eps && fabs(g2)<eps) + break; + + // Finding Newton direction: -inv(H') * g + det=h11*h22-h21*h21; + dA=-(h22*g1 - h21 * g2) / det; + dB=-(-h21*g1+ h11 * g2) / det; + gd=g1*dA+g2*dB; + + + stepsize = 1; // Line Search + while (stepsize >= min_step) + { + newA = A + stepsize * dA; + newB = B + stepsize * dB; + + // New function value + newf = 0.0; + for (i=0;i<l;i++) + { + fApB = dec_values[i]*newA+newB; + if (fApB >= 0) + newf += t[i]*fApB + log(1+exp(-fApB)); + else + newf += (t[i] - 1)*fApB +log(1+exp(fApB)); + } + // Check sufficient decrease + if (newf<fval+0.0001*stepsize*gd) + { + A=newA;B=newB;fval=newf; + break; + } + else + stepsize = stepsize / 2.0; + } + + if (stepsize < min_step) + { + info("Line search fails in two-class probability estimates\n"); + break; + } + } + + if (iter>=max_iter) + info("Reaching maximal iterations in two-class probability estimates\n"); + free(t); + } + + static double sigmoid_predict(double decision_value, double A, double B) + { + double fApB = decision_value*A+B; + // 1-p used later; avoid catastrophic cancellation + if (fApB >= 0) + return exp(-fApB)/(1.0+exp(-fApB)); + else + return 1.0/(1+exp(fApB)) ; + } + + // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng + static void multiclass_probability(int k, double **r, double *p) + { + int t,j; + int iter = 0, max_iter=max(100,k); + double **Q=Malloc(double *,k); + double *Qp=Malloc(double,k); + double pQp, eps=0.005/k; + + for (t=0;t<k;t++) + { + p[t]=1.0/k; // Valid if k = 1 + Q[t]=Malloc(double,k); + Q[t][t]=0; + for (j=0;j<t;j++) + { + Q[t][t]+=r[j][t]*r[j][t]; + Q[t][j]=Q[j][t]; + } + for (j=t+1;j<k;j++) + { + Q[t][t]+=r[j][t]*r[j][t]; + Q[t][j]=-r[j][t]*r[t][j]; + } + } + for (iter=0;iter<max_iter;iter++) + { + // stopping condition, recalculate QP,pQP for numerical accuracy + pQp=0; + for (t=0;t<k;t++) + { + Qp[t]=0; + for (j=0;j<k;j++) + Qp[t]+=Q[t][j]*p[j]; + pQp+=p[t]*Qp[t]; + } + double max_error=0; + for (t=0;t<k;t++) + { + double error=fabs(Qp[t]-pQp); + if (error>max_error) + max_error=error; + } + if (max_error<eps) break; + + for (t=0;t<k;t++) + { + double diff=(-Qp[t]+pQp)/Q[t][t]; + p[t]+=diff; + pQp=(pQp+diff*(diff*Q[t][t]+2*Qp[t]))/(1+diff)/(1+diff); + for (j=0;j<k;j++) + { + Qp[j]=(Qp[j]+diff*Q[t][j])/(1+diff); + p[j]/=(1+diff); + } + } + } + if (iter>=max_iter) + info("Exceeds max_iter in multiclass_prob\n"); + for(t=0;t<k;t++) free(Q[t]); + free(Q); + free(Qp); + } + + // Cross-validation decision values for probability estimates + static void svm_binary_svc_probability( + const svm_problem *prob, const svm_parameter *param, + double Cp, double Cn, double& probA, double& probB) + { + int i; + int nr_fold = 5; + int *perm = Malloc(int,prob->l); + double *dec_values = Malloc(double,prob->l); + + // random shuffle + for(i=0;i<prob->l;i++) perm[i]=i; + for(i=0;i<prob->l;i++) + { + int j = i+rand()%(prob->l-i); + swap(perm[i],perm[j]); + } + for(i=0;i<nr_fold;i++) + { + int begin = i*prob->l/nr_fold; + int end = (i+1)*prob->l/nr_fold; + int j,k; + struct svm_problem subprob; + + subprob.l = prob->l-(end-begin); + subprob.x = Malloc(struct svm_node*,subprob.l); + subprob.y = Malloc(double,subprob.l); + + k=0; + for(j=0;j<begin;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + for(j=end;j<prob->l;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + int p_count=0,n_count=0; + for(j=0;j<k;j++) + if(subprob.y[j]>0) + p_count++; + else + n_count++; + + if(p_count==0 && n_count==0) + for(j=begin;j<end;j++) + dec_values[perm[j]] = 0; + else if(p_count > 0 && n_count == 0) + for(j=begin;j<end;j++) + dec_values[perm[j]] = 1; + else if(p_count == 0 && n_count > 0) + for(j=begin;j<end;j++) + dec_values[perm[j]] = -1; + else + { + svm_parameter subparam = *param; + subparam.probability=0; + subparam.C=1.0; + subparam.nr_weight=2; + subparam.weight_label = Malloc(int,2); + subparam.weight = Malloc(double,2); + subparam.weight_label[0]=+1; + subparam.weight_label[1]=-1; + subparam.weight[0]=Cp; + subparam.weight[1]=Cn; + struct svm_model *submodel = svm_train(&subprob,&subparam); + for(j=begin;j<end;j++) + { + svm_predict_values(submodel,prob->x[perm[j]],&(dec_values[perm[j]])); + // ensure +1 -1 order; reason not using CV subroutine + dec_values[perm[j]] *= submodel->label[0]; + } + svm_free_and_destroy_model(&submodel); + svm_destroy_param(&subparam); + } + free(subprob.x); + free(subprob.y); + } + sigmoid_train(prob->l,dec_values,prob->y,probA,probB); + free(dec_values); + free(perm); + } + + // Return parameter of a Laplace distribution + static double svm_svr_probability( + const svm_problem *prob, const svm_parameter *param) + { + int i; + int nr_fold = 5; + double *ymv = Malloc(double,prob->l); + double mae = 0; + + svm_parameter newparam = *param; + newparam.probability = 0; + svm_cross_validation(prob,&newparam,nr_fold,ymv); + for(i=0;i<prob->l;i++) + { + ymv[i]=prob->y[i]-ymv[i]; + mae += fabs(ymv[i]); + } + mae /= prob->l; + double std=sqrt(2*mae*mae); + int count=0; + mae=0; + for(i=0;i<prob->l;i++) + if (fabs(ymv[i]) > 5*std) + count=count+1; + else + mae+=fabs(ymv[i]); + mae /= (prob->l-count); + info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma= %g\n",mae); + free(ymv); + return mae; + } + + + // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data + // perm, length l, must be allocated before calling this subroutine + static void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int **label_ret, int **start_ret, int **count_ret, int *perm) + { + int l = prob->l; + int max_nr_class = 16; + int nr_class = 0; + int *label = Malloc(int,max_nr_class); + int *count = Malloc(int,max_nr_class); + int *data_label = Malloc(int,l); + int i; + + for(i=0;i<l;i++) + { + int this_label = (int)prob->y[i]; + int j; + for(j=0;j<nr_class;j++) + { + if(this_label == label[j]) + { + ++count[j]; + break; + } + } + data_label[i] = j; + if(j == nr_class) + { + if(nr_class == max_nr_class) + { + max_nr_class *= 2; + label = (int *)realloc(label,max_nr_class*sizeof(int)); + count = (int *)realloc(count,max_nr_class*sizeof(int)); + } + label[nr_class] = this_label; + count[nr_class] = 1; + ++nr_class; + } + } + + // + // Labels are ordered by their first occurrence in the training set. + // However, for two-class sets with -1/+1 labels and -1 appears first, + // we swap labels to ensure that internally the binary SVM has positive data corresponding to the +1 instances. + // + if (nr_class == 2 && label[0] == -1 && label[1] == 1) + { + swap(label[0],label[1]); + swap(count[0],count[1]); + for(i=0;i<l;i++) + { + if(data_label[i] == 0) + data_label[i] = 1; + else + data_label[i] = 0; + } + } + + int *start = Malloc(int,nr_class); + start[0] = 0; + for(i=1;i<nr_class;i++) + start[i] = start[i-1]+count[i-1]; + for(i=0;i<l;i++) + { + perm[start[data_label[i]]] = i; + ++start[data_label[i]]; + } + start[0] = 0; + for(i=1;i<nr_class;i++) + start[i] = start[i-1]+count[i-1]; + + *nr_class_ret = nr_class; + *label_ret = label; + *start_ret = start; + *count_ret = count; + free(data_label); + } + + // + // Interface functions + // + svm_model *svm_train(const svm_problem *prob, const svm_parameter *param) + { + svm_model *model = Malloc(svm_model,1); + model->param = *param; + model->free_sv = 0; // XXX + + if(param->svm_type == ONE_CLASS || + param->svm_type == EPSILON_SVR || + param->svm_type == NU_SVR) + { + // regression or one-class-svm + model->nr_class = 2; + model->label = NULL; + model->nSV = NULL; + model->probA = NULL; model->probB = NULL; + model->sv_coef = Malloc(double *,1); + + if(param->probability && + (param->svm_type == EPSILON_SVR || + param->svm_type == NU_SVR)) + { + model->probA = Malloc(double,1); + model->probA[0] = svm_svr_probability(prob,param); + } + + decision_function f = svm_train_one(prob,param,0,0); + model->rho = Malloc(double,1); + model->rho[0] = f.rho; + + int nSV = 0; + int i; + for(i=0;i<prob->l;i++) + if(fabs(f.alpha[i]) > 0) ++nSV; + model->l = nSV; + model->SV = Malloc(svm_node *,nSV); + model->sv_coef[0] = Malloc(double,nSV); + model->sv_indices = Malloc(int,nSV); + int j = 0; + for(i=0;i<prob->l;i++) + if(fabs(f.alpha[i]) > 0) + { + model->SV[j] = prob->x[i]; + model->sv_coef[0][j] = f.alpha[i]; + model->sv_indices[j] = i+1; + ++j; + } + + free(f.alpha); + } + else + { + // classification + int l = prob->l; + int nr_class; + int *label = NULL; + int *start = NULL; + int *count = NULL; + int *perm = Malloc(int,l); + + // group training data of the same class + svm_group_classes(prob,&nr_class,&label,&start,&count,perm); + if(nr_class == 1) + info("WARNING: training data in only one class. See README for details.\n"); + + svm_node **x = Malloc(svm_node *,l); + int i; + for(i=0;i<l;i++) + x[i] = prob->x[perm[i]]; + + // calculate weighted C + + double *weighted_C = Malloc(double, nr_class); + for(i=0;i<nr_class;i++) + weighted_C[i] = param->C; + for(i=0;i<param->nr_weight;i++) + { + int j; + for(j=0;j<nr_class;j++) + if(param->weight_label[i] == label[j]) + break; + if(j == nr_class) + fprintf(stderr,"WARNING: class label %d specified in weight is not found\n", param->weight_label[i]); + else + weighted_C[j] *= param->weight[i]; + } + + // train k*(k-1)/2 models + + bool *nonzero = Malloc(bool,l); + for(i=0;i<l;i++) + nonzero[i] = false; + decision_function *f = Malloc(decision_function,nr_class*(nr_class-1)/2); + + double *probA=NULL,*probB=NULL; + if (param->probability) + { + probA=Malloc(double,nr_class*(nr_class-1)/2); + probB=Malloc(double,nr_class*(nr_class-1)/2); + } + + int p = 0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + svm_problem sub_prob; + int si = start[i], sj = start[j]; + int ci = count[i], cj = count[j]; + sub_prob.l = ci+cj; + sub_prob.x = Malloc(svm_node *,sub_prob.l); + sub_prob.y = Malloc(double,sub_prob.l); + int k; + for(k=0;k<ci;k++) + { + sub_prob.x[k] = x[si+k]; + sub_prob.y[k] = +1; + } + for(k=0;k<cj;k++) + { + sub_prob.x[ci+k] = x[sj+k]; + sub_prob.y[ci+k] = -1; + } + + if(param->probability) + svm_binary_svc_probability(&sub_prob,param,weighted_C[i],weighted_C[j],probA[p],probB[p]); + + f[p] = svm_train_one(&sub_prob,param,weighted_C[i],weighted_C[j]); + for(k=0;k<ci;k++) + if(!nonzero[si+k] && fabs(f[p].alpha[k]) > 0) + nonzero[si+k] = true; + for(k=0;k<cj;k++) + if(!nonzero[sj+k] && fabs(f[p].alpha[ci+k]) > 0) + nonzero[sj+k] = true; + free(sub_prob.x); + free(sub_prob.y); + ++p; + } + + // build output + + model->nr_class = nr_class; + + model->label = Malloc(int,nr_class); + for(i=0;i<nr_class;i++) + model->label[i] = label[i]; + + model->rho = Malloc(double,nr_class*(nr_class-1)/2); + for(i=0;i<nr_class*(nr_class-1)/2;i++) + model->rho[i] = f[i].rho; + + if(param->probability) + { + model->probA = Malloc(double,nr_class*(nr_class-1)/2); + model->probB = Malloc(double,nr_class*(nr_class-1)/2); + for(i=0;i<nr_class*(nr_class-1)/2;i++) + { + model->probA[i] = probA[i]; + model->probB[i] = probB[i]; + } + } + else + { + model->probA=NULL; + model->probB=NULL; + } + + int total_sv = 0; + int *nz_count = Malloc(int,nr_class); + model->nSV = Malloc(int,nr_class); + for(i=0;i<nr_class;i++) + { + int nSV = 0; + for(int j=0;j<count[i];j++) + if(nonzero[start[i]+j]) + { + ++nSV; + ++total_sv; + } + model->nSV[i] = nSV; + nz_count[i] = nSV; + } + + info("Total nSV = %d\n",total_sv); + + model->l = total_sv; + model->SV = Malloc(svm_node *,total_sv); + model->sv_indices = Malloc(int,total_sv); + p = 0; + for(i=0;i<l;i++) + if(nonzero[i]) + { + model->SV[p] = x[i]; + model->sv_indices[p++] = perm[i] + 1; + } + + int *nz_start = Malloc(int,nr_class); + nz_start[0] = 0; + for(i=1;i<nr_class;i++) + nz_start[i] = nz_start[i-1]+nz_count[i-1]; + + model->sv_coef = Malloc(double *,nr_class-1); + for(i=0;i<nr_class-1;i++) + model->sv_coef[i] = Malloc(double,total_sv); + + p = 0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + // classifier (i,j): coefficients with + // i are in sv_coef[j-1][nz_start[i]...], + // j are in sv_coef[i][nz_start[j]...] + + int si = start[i]; + int sj = start[j]; + int ci = count[i]; + int cj = count[j]; + + int q = nz_start[i]; + int k; + for(k=0;k<ci;k++) + if(nonzero[si+k]) + model->sv_coef[j-1][q++] = f[p].alpha[k]; + q = nz_start[j]; + for(k=0;k<cj;k++) + if(nonzero[sj+k]) + model->sv_coef[i][q++] = f[p].alpha[ci+k]; + ++p; + } + + free(label); + free(probA); + free(probB); + free(count); + free(perm); + free(start); + free(x); + free(weighted_C); + free(nonzero); + for(i=0;i<nr_class*(nr_class-1)/2;i++) + free(f[i].alpha); + free(f); + free(nz_count); + free(nz_start); + } + return model; + } + + // Stratified cross validation + void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, int nr_fold, double *target) + { + int i; + int *fold_start; + int l = prob->l; + int *perm = Malloc(int,l); + int nr_class; + if (nr_fold > l) + { + nr_fold = l; + fprintf(stderr,"WARNING: # folds > # data. Will use # folds = # data instead (i.e., leave-one-out cross validation)\n"); + } + fold_start = Malloc(int,nr_fold+1); + // stratified cv may not give leave-one-out rate + // Each class to l folds -> some folds may have zero elements + if((param->svm_type == C_SVC || + param->svm_type == NU_SVC) && nr_fold < l) + { + int *start = NULL; + int *label = NULL; + int *count = NULL; + svm_group_classes(prob,&nr_class,&label,&start,&count,perm); + + // random shuffle and then data grouped by fold using the array perm + int *fold_count = Malloc(int,nr_fold); + int c; + int *index = Malloc(int,l); + for(i=0;i<l;i++) + index[i]=perm[i]; + for (c=0; c<nr_class; c++) + for(i=0;i<count[c];i++) + { + int j = i+rand()%(count[c]-i); + swap(index[start[c]+j],index[start[c]+i]); + } + for(i=0;i<nr_fold;i++) + { + fold_count[i] = 0; + for (c=0; c<nr_class;c++) + fold_count[i]+=(i+1)*count[c]/nr_fold-i*count[c]/nr_fold; + } + fold_start[0]=0; + for (i=1;i<=nr_fold;i++) + fold_start[i] = fold_start[i-1]+fold_count[i-1]; + for (c=0; c<nr_class;c++) + for(i=0;i<nr_fold;i++) + { + int begin = start[c]+i*count[c]/nr_fold; + int end = start[c]+(i+1)*count[c]/nr_fold; + for(int j=begin;j<end;j++) + { + perm[fold_start[i]] = index[j]; + fold_start[i]++; + } + } + fold_start[0]=0; + for (i=1;i<=nr_fold;i++) + fold_start[i] = fold_start[i-1]+fold_count[i-1]; + free(start); + free(label); + free(count); + free(index); + free(fold_count); + } + else + { + for(i=0;i<l;i++) perm[i]=i; + for(i=0;i<l;i++) + { + int j = i+rand()%(l-i); + swap(perm[i],perm[j]); + } + for(i=0;i<=nr_fold;i++) + fold_start[i]=i*l/nr_fold; + } + + for(i=0;i<nr_fold;i++) + { + int begin = fold_start[i]; + int end = fold_start[i+1]; + int j,k; + struct svm_problem subprob; + + subprob.l = l-(end-begin); + subprob.x = Malloc(struct svm_node*,subprob.l); + subprob.y = Malloc(double,subprob.l); + + k=0; + for(j=0;j<begin;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + for(j=end;j<l;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + struct svm_model *submodel = svm_train(&subprob,param); + if(param->probability && + (param->svm_type == C_SVC || param->svm_type == NU_SVC)) + { + double *prob_estimates=Malloc(double,svm_get_nr_class(submodel)); + for(j=begin;j<end;j++) + target[perm[j]] = svm_predict_probability(submodel,prob->x[perm[j]],prob_estimates); + free(prob_estimates); + } + else + for(j=begin;j<end;j++) + target[perm[j]] = svm_predict(submodel,prob->x[perm[j]]); + svm_free_and_destroy_model(&submodel); + free(subprob.x); + free(subprob.y); + } + free(fold_start); + free(perm); + } + + + int svm_get_svm_type(const svm_model *model) + { + return model->param.svm_type; + } + + int svm_get_nr_class(const svm_model *model) + { + return model->nr_class; + } + + void svm_get_labels(const svm_model *model, int* label) + { + if (model->label != NULL) + for(int i=0;i<model->nr_class;i++) + label[i] = model->label[i]; + } + + void svm_get_sv_indices(const svm_model *model, int* indices) + { + if (model->sv_indices != NULL) + for(int i=0;i<model->l;i++) + indices[i] = model->sv_indices[i]; + } + + int svm_get_nr_sv(const svm_model *model) + { + return model->l; + } + + double svm_get_svr_probability(const svm_model *model) + { + if ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) && + model->probA!=NULL) + return model->probA[0]; + else + { + fprintf(stderr,"Model doesn't contain information for SVR probability inference\n"); + return 0; + } + } + + double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values) + { + int i; + if(model->param.svm_type == ONE_CLASS || + model->param.svm_type == EPSILON_SVR || + model->param.svm_type == NU_SVR) + { + double *sv_coef = model->sv_coef[0]; + double sum = 0; + for(i=0;i<model->l;i++) + sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param); + sum -= model->rho[0]; + *dec_values = sum; + + if(model->param.svm_type == ONE_CLASS) + return (sum>0)?1:-1; + else + return sum; + } + else + { + int nr_class = model->nr_class; + int l = model->l; + + double *kvalue = Malloc(double,l); + for(i=0;i<l;i++) + kvalue[i] = Kernel::k_function(x,model->SV[i],model->param); + + int *start = Malloc(int,nr_class); + start[0] = 0; + for(i=1;i<nr_class;i++) + start[i] = start[i-1]+model->nSV[i-1]; + + int *vote = Malloc(int,nr_class); + for(i=0;i<nr_class;i++) + vote[i] = 0; + + int p=0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + double sum = 0; + int si = start[i]; + int sj = start[j]; + int ci = model->nSV[i]; + int cj = model->nSV[j]; + + int k; + double *coef1 = model->sv_coef[j-1]; + double *coef2 = model->sv_coef[i]; + for(k=0;k<ci;k++) + sum += coef1[si+k] * kvalue[si+k]; + for(k=0;k<cj;k++) + sum += coef2[sj+k] * kvalue[sj+k]; + sum -= model->rho[p]; + dec_values[p] = sum; + + if(dec_values[p] > 0) + ++vote[i]; + else + ++vote[j]; + p++; + } + + int vote_max_idx = 0; + for(i=1;i<nr_class;i++) + if(vote[i] > vote[vote_max_idx]) + vote_max_idx = i; + + free(kvalue); + free(start); + free(vote); + return model->label[vote_max_idx]; + } + } + + double svm_predict(const svm_model *model, const svm_node *x) + { + int nr_class = model->nr_class; + double *dec_values; + if(model->param.svm_type == ONE_CLASS || + model->param.svm_type == EPSILON_SVR || + model->param.svm_type == NU_SVR) + dec_values = Malloc(double, 1); + else + dec_values = Malloc(double, nr_class*(nr_class-1)/2); + double pred_result = svm_predict_values(model, x, dec_values); + free(dec_values); + return pred_result; + } + + double svm_predict_probability( + const svm_model *model, const svm_node *x, double *prob_estimates) + { + if ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) && + model->probA!=NULL && model->probB!=NULL) + { + int i; + int nr_class = model->nr_class; + double *dec_values = Malloc(double, nr_class*(nr_class-1)/2); + svm_predict_values(model, x, dec_values); + + double min_prob=1e-7; + double **pairwise_prob=Malloc(double *,nr_class); + for(i=0;i<nr_class;i++) + pairwise_prob[i]=Malloc(double,nr_class); + int k=0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + pairwise_prob[i][j]=min(max(sigmoid_predict(dec_values[k],model->probA[k],model->probB[k]),min_prob),1-min_prob); + pairwise_prob[j][i]=1-pairwise_prob[i][j]; + k++; + } + if (nr_class == 2) + { + prob_estimates[0] = pairwise_prob[0][1]; + prob_estimates[1] = pairwise_prob[1][0]; + } + else + multiclass_probability(nr_class,pairwise_prob,prob_estimates); + + int prob_max_idx = 0; + for(i=1;i<nr_class;i++) + if(prob_estimates[i] > prob_estimates[prob_max_idx]) + prob_max_idx = i; + for(i=0;i<nr_class;i++) + free(pairwise_prob[i]); + free(dec_values); + free(pairwise_prob); + return model->label[prob_max_idx]; + } + else + return svm_predict(model, x); + } + + static const char *svm_type_table[] = + { + "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",NULL + }; + + static const char *kernel_type_table[]= + { + "linear","polynomial","rbf","sigmoid","precomputed",NULL + }; + + int svm_save_model(const char *model_file_name, const svm_model *model) + { + FILE *fp = fopen(model_file_name,"w"); + if(fp==NULL) return -1; + + char *old_locale = setlocale(LC_ALL, NULL); + if (old_locale) { + old_locale = strdup(old_locale); + } + setlocale(LC_ALL, "C"); + + const svm_parameter& param = model->param; + + fprintf(fp,"svm_type %s\n", svm_type_table[param.svm_type]); + fprintf(fp,"kernel_type %s\n", kernel_type_table[param.kernel_type]); + + if(param.kernel_type == POLY) + fprintf(fp,"degree %d\n", param.degree); + + if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID) + fprintf(fp,"gamma %g\n", param.gamma); + + if(param.kernel_type == POLY || param.kernel_type == SIGMOID) + fprintf(fp,"coef0 %g\n", param.coef0); + + int nr_class = model->nr_class; + int l = model->l; + fprintf(fp, "nr_class %d\n", nr_class); + fprintf(fp, "total_sv %d\n",l); + + { + fprintf(fp, "rho"); + for(int i=0;i<nr_class*(nr_class-1)/2;i++) + fprintf(fp," %g",model->rho[i]); + fprintf(fp, "\n"); + } + + if(model->label) + { + fprintf(fp, "label"); + for(int i=0;i<nr_class;i++) + fprintf(fp," %d",model->label[i]); + fprintf(fp, "\n"); + } + + if(model->probA) // regression has probA only + { + fprintf(fp, "probA"); + for(int i=0;i<nr_class*(nr_class-1)/2;i++) + fprintf(fp," %g",model->probA[i]); + fprintf(fp, "\n"); + } + if(model->probB) + { + fprintf(fp, "probB"); + for(int i=0;i<nr_class*(nr_class-1)/2;i++) + fprintf(fp," %g",model->probB[i]); + fprintf(fp, "\n"); + } + + if(model->nSV) + { + fprintf(fp, "nr_sv"); + for(int i=0;i<nr_class;i++) + fprintf(fp," %d",model->nSV[i]); + fprintf(fp, "\n"); + } + + fprintf(fp, "SV\n"); + const double * const *sv_coef = model->sv_coef; + const svm_node * const *SV = model->SV; + + for(int i=0;i<l;i++) + { + for(int j=0;j<nr_class-1;j++) + fprintf(fp, "%.16g ",sv_coef[j][i]); + + const svm_node *p = SV[i]; + + if(param.kernel_type == PRECOMPUTED) + fprintf(fp,"0:%d ",(int)(p->value)); + else + while(p->index != -1) + { + fprintf(fp,"%d:%.8g ",p->index,p->value); + p++; + } + fprintf(fp, "\n"); + } + + setlocale(LC_ALL, old_locale); + free(old_locale); + + if (ferror(fp) != 0 || fclose(fp) != 0) return -1; + else return 0; + } + + static char *line = NULL; + static int max_line_len; + + static char* readline(FILE *input) + { + int len; + + if(fgets(line,max_line_len,input) == NULL) + return NULL; + + while(strrchr(line,'\n') == NULL) + { + max_line_len *= 2; + line = (char *) realloc(line,max_line_len); + len = (int) strlen(line); + if(fgets(line+len,max_line_len-len,input) == NULL) + break; + } + return line; + } + + // + // FSCANF helps to handle fscanf failures. + // Its do-while block avoids the ambiguity when + // if (...) + // FSCANF(); + // is used + // +#define FSCANF(_stream, _format, _var) do{ if (fscanf(_stream, _format, _var) != 1) return false; }while(0) + bool read_model_header(FILE *fp, svm_model* model) + { + svm_parameter& param = model->param; + // parameters for training only won't be assigned, but arrays are assigned as NULL for safety + param.nr_weight = 0; + param.weight_label = NULL; + param.weight = NULL; + + char cmd[81]; + while(1) + { + FSCANF(fp,"%80s",cmd); + + if(strcmp(cmd,"svm_type")==0) + { + FSCANF(fp,"%80s",cmd); + int i; + for(i=0;svm_type_table[i];i++) + { + if(strcmp(svm_type_table[i],cmd)==0) + { + param.svm_type=i; + break; + } + } + if(svm_type_table[i] == NULL) + { + fprintf(stderr,"unknown svm type.\n"); + return false; + } + } + else if(strcmp(cmd,"kernel_type")==0) + { + FSCANF(fp,"%80s",cmd); + int i; + for(i=0;kernel_type_table[i];i++) + { + if(strcmp(kernel_type_table[i],cmd)==0) + { + param.kernel_type=i; + break; + } + } + if(kernel_type_table[i] == NULL) + { + fprintf(stderr,"unknown kernel function.\n"); + return false; + } + } + else if(strcmp(cmd,"degree")==0) + FSCANF(fp,"%d",¶m.degree); + else if(strcmp(cmd,"gamma")==0) + FSCANF(fp,"%lf",¶m.gamma); + else if(strcmp(cmd,"coef0")==0) + FSCANF(fp,"%lf",¶m.coef0); + else if(strcmp(cmd,"nr_class")==0) + FSCANF(fp,"%d",&model->nr_class); + else if(strcmp(cmd,"total_sv")==0) + FSCANF(fp,"%d",&model->l); + else if(strcmp(cmd,"rho")==0) + { + int n = model->nr_class * (model->nr_class-1)/2; + model->rho = Malloc(double,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%lf",&model->rho[i]); + } + else if(strcmp(cmd,"label")==0) + { + int n = model->nr_class; + model->label = Malloc(int,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%d",&model->label[i]); + } + else if(strcmp(cmd,"probA")==0) + { + int n = model->nr_class * (model->nr_class-1)/2; + model->probA = Malloc(double,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%lf",&model->probA[i]); + } + else if(strcmp(cmd,"probB")==0) + { + int n = model->nr_class * (model->nr_class-1)/2; + model->probB = Malloc(double,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%lf",&model->probB[i]); + } + else if(strcmp(cmd,"nr_sv")==0) + { + int n = model->nr_class; + model->nSV = Malloc(int,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%d",&model->nSV[i]); + } + else if(strcmp(cmd,"SV")==0) + { + while(1) + { + int c = getc(fp); + if(c==EOF || c=='\n') break; + } + break; + } + else + { + fprintf(stderr,"unknown text in model file: [%s]\n",cmd); + return false; + } + } + + return true; + + } + + svm_model *svm_load_model(const char *model_file_name) + { + FILE *fp = fopen(model_file_name,"rb"); + if(fp==NULL) return NULL; + + char *old_locale = setlocale(LC_ALL, NULL); + if (old_locale) { + old_locale = strdup(old_locale); + } + setlocale(LC_ALL, "C"); + + // read parameters + + svm_model *model = Malloc(svm_model,1); + model->rho = NULL; + model->probA = NULL; + model->probB = NULL; + model->sv_indices = NULL; + model->label = NULL; + model->nSV = NULL; + + // read header + if (!read_model_header(fp, model)) + { + fprintf(stderr, "ERROR: fscanf failed to read model\n"); + setlocale(LC_ALL, old_locale); + free(old_locale); + free(model->rho); + free(model->label); + free(model->nSV); + free(model); + return NULL; + } + + // read sv_coef and SV + + int elements = 0; + long pos = ftell(fp); + + max_line_len = 1024; + line = Malloc(char,max_line_len); + char *p,*endptr,*idx,*val; + + while(readline(fp)!=NULL) + { + p = strtok(line,":"); + while(1) + { + p = strtok(NULL,":"); + if(p == NULL) + break; + ++elements; + } + } + elements += model->l; + + fseek(fp,pos,SEEK_SET); + + int m = model->nr_class - 1; + int l = model->l; + model->sv_coef = Malloc(double *,m); + int i; + for(i=0;i<m;i++) + model->sv_coef[i] = Malloc(double,l); + model->SV = Malloc(svm_node*,l); + svm_node *x_space = NULL; + if(l>0) x_space = Malloc(svm_node,elements); + + int j=0; + for(i=0;i<l;i++) + { + readline(fp); + model->SV[i] = &x_space[j]; + + p = strtok(line, " \t"); + model->sv_coef[0][i] = strtod(p,&endptr); + for(int k=1;k<m;k++) + { + p = strtok(NULL, " \t"); + model->sv_coef[k][i] = strtod(p,&endptr); + } + + while(1) + { + idx = strtok(NULL, ":"); + val = strtok(NULL, " \t"); + + if(val == NULL) + break; + x_space[j].index = (int) strtol(idx,&endptr,10); + x_space[j].value = strtod(val,&endptr); + + ++j; + } + x_space[j++].index = -1; + } + free(line); + + setlocale(LC_ALL, old_locale); + free(old_locale); + + if (ferror(fp) != 0 || fclose(fp) != 0) + return NULL; + + model->free_sv = 1; // XXX + return model; + } + + void svm_free_model_content(svm_model* model_ptr) + { + if(model_ptr->free_sv && model_ptr->l > 0 && model_ptr->SV != NULL) + free((void *)(model_ptr->SV[0])); + if(model_ptr->sv_coef) + { + for(int i=0;i<model_ptr->nr_class-1;i++) + free(model_ptr->sv_coef[i]); + } + + free(model_ptr->SV); + model_ptr->SV = NULL; + + free(model_ptr->sv_coef); + model_ptr->sv_coef = NULL; + + free(model_ptr->rho); + model_ptr->rho = NULL; + + free(model_ptr->label); + model_ptr->label= NULL; + + free(model_ptr->probA); + model_ptr->probA = NULL; + + free(model_ptr->probB); + model_ptr->probB= NULL; + + free(model_ptr->sv_indices); + model_ptr->sv_indices = NULL; + + free(model_ptr->nSV); + model_ptr->nSV = NULL; + } + + void svm_free_and_destroy_model(svm_model** model_ptr_ptr) + { + if(model_ptr_ptr != NULL && *model_ptr_ptr != NULL) + { + svm_free_model_content(*model_ptr_ptr); + free(*model_ptr_ptr); + *model_ptr_ptr = NULL; + } + } + + void svm_destroy_param(svm_parameter* param) + { + free(param->weight_label); + free(param->weight); + } + + const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *param) + { + // svm_type + + int svm_type = param->svm_type; + if(svm_type != C_SVC && + svm_type != NU_SVC && + svm_type != ONE_CLASS && + svm_type != EPSILON_SVR && + svm_type != NU_SVR) + return "unknown svm type"; + + // kernel_type, degree + + int kernel_type = param->kernel_type; + if(kernel_type != LINEAR && + kernel_type != POLY && + kernel_type != RBF && + kernel_type != SIGMOID && + kernel_type != PRECOMPUTED) + return "unknown kernel type"; + + if(param->gamma < 0) + return "gamma < 0"; + + if(param->degree < 0) + return "degree of polynomial kernel < 0"; + + // cache_size,eps,C,nu,p,shrinking + + if(param->cache_size <= 0) + return "cache_size <= 0"; + + if(param->eps <= 0) + return "eps <= 0"; + + if(svm_type == C_SVC || + svm_type == EPSILON_SVR || + svm_type == NU_SVR) + if(param->C <= 0) + return "C <= 0"; + + if(svm_type == NU_SVC || + svm_type == ONE_CLASS || + svm_type == NU_SVR) + if(param->nu <= 0 || param->nu > 1) + return "nu <= 0 or nu > 1"; + + if(svm_type == EPSILON_SVR) + if(param->p < 0) + return "p < 0"; + + if(param->shrinking != 0 && + param->shrinking != 1) + return "shrinking != 0 and shrinking != 1"; + + if(param->probability != 0 && + param->probability != 1) + return "probability != 0 and probability != 1"; + + if(param->probability == 1 && + svm_type == ONE_CLASS) + return "one-class SVM probability output not supported yet"; + + + // check whether nu-svc is feasible + + if(svm_type == NU_SVC) + { + int l = prob->l; + int max_nr_class = 16; + int nr_class = 0; + int *label = Malloc(int,max_nr_class); + int *count = Malloc(int,max_nr_class); + + int i; + for(i=0;i<l;i++) + { + int this_label = (int)prob->y[i]; + int j; + for(j=0;j<nr_class;j++) + if(this_label == label[j]) + { + ++count[j]; + break; + } + if(j == nr_class) + { + if(nr_class == max_nr_class) + { + max_nr_class *= 2; + label = (int *)realloc(label,max_nr_class*sizeof(int)); + count = (int *)realloc(count,max_nr_class*sizeof(int)); + } + label[nr_class] = this_label; + count[nr_class] = 1; + ++nr_class; + } + } + + for(i=0;i<nr_class;i++) + { + int n1 = count[i]; + for(int j=i+1;j<nr_class;j++) + { + int n2 = count[j]; + if(param->nu*(n1+n2)/2 > min(n1,n2)) + { + free(label); + free(count); + return "specified nu is infeasible"; + } + } + } + free(label); + free(count); + } + + return NULL; + } + + int svm_check_probability_model(const svm_model *model) + { + return ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) && + model->probA!=NULL && model->probB!=NULL) || + ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) && + model->probA!=NULL); + } + + void svm_set_print_string_function(void (*print_func)(const char *)) + { + if(print_func == NULL) + svm_print_string = &print_string_stdout; + else + svm_print_string = print_func; + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/libsvm/libsvm.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/libsvm/libsvm.h new file mode 100644 index 0000000000000000000000000000000000000000..b1f583202b3d49fd30957ad7d4e6aea9804aad9e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/dependencies/libsvm/libsvm.h @@ -0,0 +1,108 @@ +#ifndef _LIBSVM_H +#define _LIBSVM_H + +namespace LIBSVM { + +#define LIBSVM_VERSION 322 + +#ifdef __cplusplus + extern "C" { +#endif + + extern int libsvm_version; + + struct svm_node + { + int index; + double value; + }; + + struct svm_problem + { + int l; + double *y; + struct svm_node **x; + }; + + enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR }; /* svm_type */ + enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED }; /* kernel_type */ + + struct svm_parameter + { + int svm_type; + int kernel_type; + int degree; /* for poly */ + double gamma; /* for poly/rbf/sigmoid */ + double coef0; /* for poly/sigmoid */ + + /* these are for training only */ + double cache_size; /* in MB */ + double eps; /* stopping criteria */ + double C; /* for C_SVC, EPSILON_SVR and NU_SVR */ + int nr_weight; /* for C_SVC */ + int *weight_label; /* for C_SVC */ + double* weight; /* for C_SVC */ + double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */ + double p; /* for EPSILON_SVR */ + int shrinking; /* use the shrinking heuristics */ + int probability; /* do probability estimates */ + }; + + // + // svm_model + // + struct svm_model + { + struct svm_parameter param; /* parameter */ + int nr_class; /* number of classes, = 2 in regression/one class svm */ + int l; /* total #SV */ + struct svm_node **SV; /* SVs (SV[l]) */ + double **sv_coef; /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */ + double *rho; /* constants in decision functions (rho[k*(k-1)/2]) */ + double *probA; /* pariwise probability information */ + double *probB; + int *sv_indices; /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */ + + /* for classification only */ + + int *label; /* label of each class (label[k]) */ + int *nSV; /* number of SVs for each class (nSV[k]) */ + /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ + /* XXX */ + int free_sv; /* 1 if svm_model is created by svm_load_model*/ + /* 0 if svm_model is created by svm_train */ + }; + + struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param); + void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter *param, int nr_fold, double *target); + + int svm_save_model(const char *model_file_name, const struct svm_model *model); + struct svm_model *svm_load_model(const char *model_file_name); + + int svm_get_svm_type(const struct svm_model *model); + int svm_get_nr_class(const struct svm_model *model); + void svm_get_labels(const struct svm_model *model, int *label); + void svm_get_sv_indices(const struct svm_model *model, int *sv_indices); + int svm_get_nr_sv(const struct svm_model *model); + double svm_get_svr_probability(const struct svm_model *model); + + double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values); + double svm_predict(const struct svm_model *model, const struct svm_node *x); + double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates); + + void svm_free_model_content(struct svm_model *model_ptr); + void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr); + void svm_destroy_param(struct svm_parameter *param); + + const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param); + int svm_check_probability_model(const struct svm_model *model); + + void svm_set_print_string_function(void (*print_func)(const char *)); + +#ifdef __cplusplus + } +#endif + +} + +#endif /* _LIBSVM_H */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/baseModel.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/baseModel.h new file mode 100644 index 0000000000000000000000000000000000000000..9ca7461291b888fd89f80d84b6715c58d7adb246 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/baseModel.h @@ -0,0 +1,47 @@ +/** + * @file baseModel.h + * RapidLib + * + * @author Michael Zbyszynski + * @date 5 Sep 2016 + * @copyright Copyright © 2016 Goldsmiths. All rights reserved. + */ + + +#ifndef baseModel_h +#define baseModel_h + +#include <vector> +#include "trainingExample.h" + +#ifndef EMSCRIPTEN +#include "../dependencies/json/json.h" +#endif + +/** Base class for wekinator models. Implemented by NN and KNN classes */ +template<typename T> +class baseModel { +public: + virtual ~baseModel() {}; + virtual T run(const std::vector<T> &inputVector) = 0; + virtual void train(const std::vector<trainingExampleTemplate<T> > &trainingSet) = 0; + virtual void reset() = 0;; + virtual int getNumInputs() const = 0; + virtual std::vector<int> getWhichInputs() const = 0; + +#ifndef EMSCRIPTEN + virtual void getJSONDescription(Json::Value ¤tModel) = 0; + +protected: + template<typename TT> + Json::Value vector2json(TT vec) { + Json::Value toReturn; + for (int i = 0; i < vec.size(); ++i) { + toReturn.append(vec[i]); + } + return toReturn; + } +#endif + +}; +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/classification.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/classification.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70855e120c5e004b11c80da0e6799683772c79eb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/classification.cpp @@ -0,0 +1,107 @@ +// +// classification.h +// RapidLib +// +// Created by mzed on 26/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + + +#include <vector> +#include "classification.h" +#ifdef EMSCRIPTEN +#include "emscripten/classificationEmbindings.h" +#endif + +template<typename T> +classificationTemplate<T>::classificationTemplate() { + modelSet<T>::numInputs = 0; + modelSet<T>::numOutputs = 0; + modelSet<T>::created = false; + classificationType = knn; //this is the default algorithm +}; + +template<typename T> +classificationTemplate<T>::classificationTemplate(classificationTypes classification_type) { + modelSet<T>::numInputs = 0; + modelSet<T>::numOutputs = 0; + modelSet<T>::created = false; + classificationType = classification_type; +}; + +template<typename T> +classificationTemplate<T>::classificationTemplate(const int &num_inputs, const int &num_outputs) { //TODO: this feature isn't really useful + modelSet<T>::numInputs = num_inputs; + modelSet<T>::numOutputs = num_outputs; + modelSet<T>::created = false; + std::vector<int> whichInputs; + for (int i = 0; i < modelSet<T>::numInputs; ++i) { + whichInputs.push_back(i); + } + std::vector<trainingExampleTemplate<T> > trainingSet; + for (int i = 0; i < modelSet<T>::numOutputs; ++i) { + modelSet<T>::myModelSet.push_back(new knnClassification<T>(modelSet<T>::numInputs, whichInputs, trainingSet, 1)); + } + modelSet<T>::created = true; +}; + +template<typename T> +classificationTemplate<T>::classificationTemplate(const std::vector<trainingExampleTemplate<T> > &trainingSet) { + modelSet<T>::numInputs = 0; + modelSet<T>::numOutputs = 0; + modelSet<T>::created = false; + train(trainingSet); +}; + +template<typename T> +bool classificationTemplate<T>::train(const std::vector<trainingExampleTemplate<T> > &trainingSet) { + //TODO: time this process? + modelSet<T>::myModelSet.clear(); + //create model(s) here + modelSet<T>::numInputs = int(trainingSet[0].input.size()); + for (int i = 0; i < modelSet<T>::numInputs; ++i) { + modelSet<T>::inputNames.push_back("inputs-" + std::to_string(i + 1)); + } + modelSet<T>::numOutputs = int(trainingSet[0].output.size()); + for ( auto example : trainingSet) { + if (example.input.size() != modelSet<T>::numInputs) { + return false; + } + if (example.output.size() != modelSet<T>::numOutputs) { + return false; + } + } + std::vector<int> whichInputs; + for (int j = 0; j < modelSet<T>::numInputs; ++j) { + whichInputs.push_back(j); + } + for (int i = 0; i < modelSet<T>::numOutputs; ++i) { + if (classificationType == svm) { + modelSet<T>::myModelSet.push_back(new svmClassification<T>(modelSet<T>::numInputs)); + } else { + modelSet<T>::myModelSet.push_back(new knnClassification<T>(modelSet<T>::numInputs, whichInputs, trainingSet, 1)); + } + } + modelSet<T>::created = true; + return modelSet<T>::train(trainingSet); +} + +template<typename T> +std::vector<int> classificationTemplate<T>::getK() { + std::vector<int> kVector; + for (baseModel<T>* model : modelSet<T>::myModelSet) { + knnClassification<T>* kNNModel = dynamic_cast<knnClassification<T>*>(model); //FIXME: I really dislike this design + kVector.push_back(kNNModel->getK()); + } + return kVector; +} + +template<typename T> +void classificationTemplate<T>::setK(const int whichModel, const int newK) { + knnClassification<T>* kNNModel = dynamic_cast<knnClassification<T>*>(modelSet<T>::myModelSet[whichModel]); //FIXME: I really dislike this design + kNNModel->setK(newK); +} + +//explicit instantiation +template class classificationTemplate<double>; +template class classificationTemplate<float>; diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/classification.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/classification.h new file mode 100644 index 0000000000000000000000000000000000000000..21ba5acdfa50c9587e8a249cc5bc1efd97f5405f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/classification.h @@ -0,0 +1,57 @@ +// +// classification.h +// RapidLib +// +// Created by mzed on 26/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef classification_h +#define classification_h + +#include <vector> +#include "modelSet.h" + +/*! Class for implementing a set of classification models. + * + * This doesn't do anything modelSet can't do. But, it's simpler and more like wekinator. + */ + +template<typename T> +class classificationTemplate : public modelSet<T> { +public: + enum classificationTypes { knn, svm }; + + /** with no arguments, just make an empty vector */ + classificationTemplate(); + + /** speciify classification type */ + classificationTemplate(classificationTypes classificationType); + + /** create based on training set inputs and outputs */ + classificationTemplate(const std::vector<trainingExampleTemplate<T> > &trainingSet); + /** create with proper models, but not trained */ + classificationTemplate(const int &numInputs, const int &numOutputs); + + /** destructor */ + ~classificationTemplate() {} + + /** Train on a specified set, causes creation if not created */ + bool train(const std::vector<trainingExampleTemplate<T> > &trainingSet); + + /** Check the K values for each model. This feature is temporary, and will be replaced by a different design. */ + std::vector<int> getK(); + /** Get the K values for each model. This feature is temporary, and will be replaced by a different design. */ + void setK(const int whichModel, const int newK); + + + +private: + classificationTypes classificationType; +}; + +//This is here so that the old API still works as expected. +using classification = classificationTemplate<double>; +using classificationFloat = classificationTemplate<float>; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/dtw.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/dtw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da4b5e01337fb99d877f5e6ef66a1b5047d1bde3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/dtw.cpp @@ -0,0 +1,153 @@ +/** + * @file dtw.cpp + * RapidLib + * + * @author Michael Zbyszynski + * @date 07 Jun 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include <vector> +#include <cmath> +#include <cassert> +#include "dtw.h" + +template<typename T> +dtw<T>::dtw() {}; + +template<typename T> +dtw<T>::~dtw() {}; + +template<typename T> +inline T dtw<T>::distanceFunction(const std::vector<T> &x, const std::vector<T> &y) { + assert(x.size() == y.size()); + T euclidianDistance = 0; + for(int j = 0; j < x.size() ; ++j){ + euclidianDistance = euclidianDistance + pow((x[j] - y[j]), 2); + } + euclidianDistance = sqrt(euclidianDistance); + return euclidianDistance; +}; + +/* Just returns the cost, doesn't calculate the path */ +template<typename T> +T dtw<T>::getCost(const std::vector<std::vector<T> > &seriesX, const std::vector<std::vector<T> > &seriesY) { + if (seriesX.size() < seriesY.size()) { + return getCost(seriesY, seriesX); + } + + costMatrix.clear(); + for (int i = 0; i < seriesX.size(); ++i) { + std::vector<T> tempVector; + for (int j = 0; j < seriesY.size(); ++j) { + tempVector.push_back(0); + } + costMatrix.push_back(tempVector); + } + int maxX = int(seriesX.size()) - 1; + int maxY = int(seriesY.size()) - 1; + + //Calculate values for the first column + costMatrix[0][0] = distanceFunction(seriesX[0], seriesY[0]); + for (int j = 1; j <= maxY; ++j) { + costMatrix[0][j] = costMatrix[0][j - 1] + distanceFunction(seriesX[0], seriesY[j]); + } + + for (int i = 1; i <= maxX; ++i) { + //Bottom row of current column + costMatrix[i][0] = costMatrix[i - 1][0] + distanceFunction(seriesX[i], seriesY[0]); + for (int j = 1; j <= maxY; ++j) { + T minGlobalCost = fmin(costMatrix[i-1][j-1], costMatrix[i][j-1]); + costMatrix[i][j] = minGlobalCost + distanceFunction(seriesX[i], seriesY[j]); + } + } + return costMatrix[maxX][maxY]; +}; + +template<typename T> +warpPath dtw<T>::calculatePath(int seriesXsize, int seriesYsize) { + warpPath warpPath; + int i = seriesXsize - 1; + int j = seriesYsize - 1; + warpPath.add(i, j); + + while ((i > 0) || (j > 0)) { + T diagonalCost = std::numeric_limits<T>::infinity(); + T leftCost = std::numeric_limits<T>::infinity(); + T downCost = std::numeric_limits<T>::infinity(); + if ((i > 0) && (j > 0)) { + diagonalCost = costMatrix[i - 1][j - 1]; + } + if (i > 0) { + leftCost = costMatrix[i - 1][j]; + } + if (j > 0) { + downCost = costMatrix[i][j - 1]; + } + if ((diagonalCost <= leftCost) && (diagonalCost <= downCost)) { + i--; + j--; + } else if ((leftCost < diagonalCost) && (leftCost < downCost)){ + i--; + } else if ((downCost < diagonalCost) && (downCost < leftCost)) { + j--; + } else if (i <= j) { + j--; + } else { + i--; + } + warpPath.add(i, j); + } + return warpPath; +}; + +/* calculates both the cost and the warp path*/ +template<typename T> +warpInfo dtw<T>::dynamicTimeWarp(const std::vector<std::vector<T> > &seriesX, const std::vector<std::vector<T> > &seriesY) { + warpInfo info; + //calculate cost matrix + info.cost = getCost(seriesX, seriesY); + info.path = calculatePath(int(seriesX.size()), int(seriesY.size())); + return info; +} + +/* calculates warp info based on window */ +template<typename T> +warpInfo dtw<T>::constrainedDTW(const std::vector<std::vector<T> > &seriesX, const std::vector<std::vector<T> > &seriesY, searchWindow<T> window) { + + //initialize cost matrix + costMatrix.clear(); + for (int i = 0; i < seriesX.size(); ++i) { //TODO: this could be smaller, since most cells are unused + std::vector<T> tempVector; + for (int j = 0; j < seriesY.size(); ++j) { + tempVector.push_back(std::numeric_limits<T>::max()); + } + costMatrix.push_back(tempVector); + } + int maxX = int(seriesX.size()) - 1; + int maxY = int(seriesY.size()) - 1; + + //fill cost matrix cells based on window + for (int currentX = 0; currentX < window.minValues.size(); ++currentX) { + for (int currentY = window.minValues[currentX]; currentY <= window.maxValues[currentX]; ++currentY) { //FIXME: should be <= ? + if (currentX == 0 && currentY == 0) { //bottom left cell + costMatrix[0][0] = distanceFunction(seriesX[0], seriesY[0]); + } else if (currentX == 0) { //first column + costMatrix[0][currentY] = distanceFunction(seriesX[0], seriesY[currentY]) + costMatrix[0][currentY - 0]; + } else if (currentY == 0) { //first row + costMatrix[currentX][0] = distanceFunction(seriesX[currentX], seriesY[0]) + costMatrix[currentX - 1][0]; + } else { + T minGlobalCost = fmin(costMatrix[currentX - 1][currentY], fmin(costMatrix[currentX-1][currentY-1], costMatrix[currentX][currentY-1])); + costMatrix[currentX][currentY] = distanceFunction(seriesX[currentX], seriesY[currentY]) + minGlobalCost; + } + } + } + warpInfo info; + info.cost = costMatrix[maxX][maxY]; + info.path = calculatePath(int(seriesX.size()), int(seriesY.size())); + return info; +} + +//explicit instantiation +template class dtw<double>; +template class dtw<float>; diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/dtw.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/dtw.h new file mode 100644 index 0000000000000000000000000000000000000000..a93e25bd9bd4d688cf13b0d83c6a3c62a284ca9a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/dtw.h @@ -0,0 +1,38 @@ +/** + * @file dtw.h + * RapidLib + * + * @author Michael Zbyszynski + * @date 07 Jun 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef dtw_h +#define dtw_h + +#include <vector> +#include "warpPath.h" +#include "searchWindow.h" + +template<typename T> +class dtw { +public: + dtw(); + ~dtw(); + + /* Calculates and returns a simple cost value between two input series */ + T getCost(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY); + + /* Calculates both cost and the warp path */ + warpInfo dynamicTimeWarp(const std::vector<std::vector<T> > &seriesX, const std::vector<std::vector<T> > &seriesY); //This returns everything, including a path + + /* Calculates both the cost and the warp path, with a given window as a constraint */ + warpInfo constrainedDTW(const std::vector<std::vector<T> > &seriesX, const std::vector<std::vector<T> > &seriesY, searchWindow<T> window); //This takes a window object + +private: + inline T distanceFunction(const std::vector<T> &pointX, const std::vector<T> &point); + std::vector<std::vector<T> > costMatrix; + warpPath calculatePath(int seriesXsize, int seriesYsize); +}; + +#endif /* dtw_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/classificationEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/classificationEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..ba4be9a3479f9313be0efc24dd1507c4ee5650ba --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/classificationEmbindings.h @@ -0,0 +1,34 @@ +// +// classificationEmbindings.cpp +// RapidLib +// +// Created by mzed on 27/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + + +#ifndef classificationEmbindings_h +#define classificationEmbindings_h + +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(classification_module) { + class_<classificationTemplate<double>, base<modelSet<double> > >("ClassificationCpp") //name change so that I can wrap it in Javascript. -mz + .constructor() + .constructor<classificationTemplate<double>::classificationTypes>() + // .constructor< std::vector<trainingExample> >() + .constructor<int, int>() + .function("train", &classificationTemplate<double>::train) + .function("getK", &classificationTemplate<double>::getK) + .function("setK", &classificationTemplate<double>::setK) + ; + enum_<classificationTemplate<double>::classificationTypes>("ClassificationTypes") + .value("KNN", classificationTemplate<double>::knn) + .value("SVM", classificationTemplate<double>::svm) + ; + +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/knnEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/knnEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..7024381ff6664bb64ed9229c7762ff6488b4946e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/knnEmbindings.h @@ -0,0 +1,45 @@ +// +// knnEmbindings.h +// RapidLib +// +// Created by mzed on 05/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef knnEmbindings_h +#define knnEmbindings_h + +#include <vector> +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(stl_wrappers) { + register_vector<int>("VectorInt"); + register_vector<double>("VectorDouble"); + register_vector<std::vector<double>>("VectorVectorDouble"); + + register_vector<trainingExampleTemplate<double>>("TrainingSet"); + register_vector<trainingSeriesTemplate<double>>("TrainingSeriesSet"); + + value_object<trainingExampleTemplate<double>>("trainingExample") + .field("input", &trainingExampleTemplate<double>::input) + .field("output", &trainingExampleTemplate<double>::output) + ; + + value_object<trainingSeriesTemplate<double>>("trainingSeries") + .field("input", &trainingSeriesTemplate<double>::input) + .field("label", &trainingSeriesTemplate<double>::label) + ; +} + + +EMSCRIPTEN_BINDINGS(knn_module) { + class_<knnClassification<double>>("KnnClassification") + .constructor<int, std::vector<int>, std::vector<trainingExampleTemplate<double>>, int>() + .function("addNeighbour", &knnClassification<double>::addNeighbour) + .function("run", &knnClassification<double>::run) + ; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/modelSetEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/modelSetEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..97a098ea49541a7caba59a777e32de6f5c5f298f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/modelSetEmbindings.h @@ -0,0 +1,26 @@ +// +// modelSetEmbindings.h +// RapidLib +// +// Created by mzed on 04/10/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef modelSetEmbindings_h +#define modelSetEmbindings_h + +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(modelSet_module) { + class_<modelSet<double> >("ModelSetCpp") //name change so that I can wrap it in Javascript. -mz + .constructor() + .function("train", &modelSet<double>::train) + .function("reset", &modelSet<double>::reset) + .function("run", &modelSet<double>::run) + ; + +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/nnEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/nnEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..eeacc1b9d8a88fba5e72e1f826fab3390a3ca213 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/nnEmbindings.h @@ -0,0 +1,26 @@ +// +// nnEmbindings.h +// RapidLib +// +// Created by mzed on 22/08/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef nnEmbindings_h +#define nnEmbindings_h + +#include <vector> +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(nn_module) { + class_<neuralNetwork<double>>("NeuralNetwork") + .constructor<int, std::vector<int>, int, int>() + .constructor<int, std::vector<int>, int, int, std::vector<double>, std::vector<double>, std::vector<double>, std::vector<double>, double, double>() + .function("run", &neuralNetwork<double>::run) + .function("train", &neuralNetwork<double>::train) + ; + +}; +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/nodeEnv.js b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/nodeEnv.js new file mode 100644 index 0000000000000000000000000000000000000000..c33d2f5cd51e462a4b4781b9d156ee072b2c2aab --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/nodeEnv.js @@ -0,0 +1,7 @@ +//Forces the environment to be Node, to run with babel-tape-runner + +try { + Module.ENVIRONMENT = NODE; +} catch (e) { + // do nothing +} \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/rapidLibPost.js b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/rapidLibPost.js new file mode 100644 index 0000000000000000000000000000000000000000..fe01d0b2b4d1e1a1ca53890b1e691749070d8f81 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/rapidLibPost.js @@ -0,0 +1,629 @@ +// +// rapidLibPost.js +// RapidLib +// +// Created by mzed on 05/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +/* globals Module */ + +"use strict"; + +console.log("RapidLib 15.11.2017 14:40"); + +/** + * Utility function to convert js objects into C++ trainingSets + * @param {Object} trainingSet - JS Object representing a training set + * @property {function} Module.TrainingSet - constructor for emscripten version of this struct + * @property {function} Module.VectorDouble - constructor for the emscripten version of std::vector<double> + * @returns {Module.TrainingSet} + */ +Module.prepTrainingSet = function (trainingSet) { + let rmTrainingSet = new Module.TrainingSet(); + for (let i = 0; i < trainingSet.length; ++i) { + let tempInput = new Module.VectorDouble(); + let tempOutput = new Module.VectorDouble(); + for (let j = 0; j < trainingSet[i].input.length; ++j) { + tempInput.push_back(parseFloat(trainingSet[i].input[j])); + } + for (let j = 0; j < trainingSet[i].output.length; ++j) { + tempOutput.push_back(parseFloat(trainingSet[i].output[j])); + } + let tempObj = {'input': tempInput, 'output': tempOutput}; + rmTrainingSet.push_back(tempObj); + } + return rmTrainingSet; +}; + +/** + * Utility function to convert js objects into C++ trainingSeriesSets + * @param {Object} trainingSeriesSet - JS Object representing a training series + * @property {function} Module.TrainingSeriest - constructor for emscripten version of this struct + * @property {function} Module.VectorVectorDouble - constructor for the emscripten version of std::vector<std::vector<double>> + * @returns {Module.TrainingSeriesSet} + */ +Module.prepTrainingSeriesSet = function (trainingSeriesSet) { + let rmTrainingSeriesSet = new Module.TrainingSeriesSet(); + for (let i = 0; i < trainingSeriesSet.length; ++i) { + let input = new Module.VectorVectorDouble(); + for (let j = 0; j < trainingSeriesSet[i].input.length; ++j) { + let tempVector = new Module.VectorDouble(); + for (let k = 0; k < trainingSeriesSet[i].input[j].length; ++k) { + tempVector.push_back(parseFloat(trainingSeriesSet[i].input[j][k])); + } + input.push_back(tempVector); + } + let tempObj = {'input': input, 'label': trainingSeriesSet[i].label}; + rmTrainingSeriesSet.push_back(tempObj); + } + return rmTrainingSeriesSet; +}; + +/** + * Utility function to add an empty output to a "training set" if it is undefined + * @param jsInput + * @returns {*} + */ + +Module.checkOutput = function (jsInput) { + for (let i = 0; i < jsInput.length; ++i) { + if (typeof jsInput[i].output === "undefined") { + jsInput[i].output = []; + } + } + return jsInput; +}; +//////////////////////////////////////////////// Regression + +/** + * Creates a set of regression objects using the constructor from emscripten + * @constructor + * @property {function} Module.RegressionCpp - constructor from emscripten + */ +Module.Regression = function () { + this.modelSet = new Module.RegressionCpp(); //TODO implement optional arguments +}; + +Module.Regression.prototype = { + /** + * Trains the models using the input. Starts training from a randomized state. + * @param {Object} trainingSet - An array of training examples + * @returns {Boolean} true indicates successful training + */ + train: function (trainingSet) { + this.modelSet.reset(); + //change to vectorDoubles and send in + return this.modelSet.train(Module.prepTrainingSet(trainingSet)); + }, + /** + * Returns the number of hidden layers in a MLP. + * @returns {Number} k values + */ + getNumHiddenLayers: function () { + let outputVector = this.modelSet.getNumHiddenLayers(); + //change back to javascript array + let output = []; + for (let i = 0; i < outputVector.size(); ++i) { + output.push(outputVector.get(i)); + } + return output[0]; + }, + /** + * Sets the number of hidden layers for an MLP. + * @param {Number} numHiddenLayers + */ + setNumHiddenLayers: function (numHiddenLayers) { + this.modelSet.setNumHiddenLayers(numHiddenLayers); + }, + /** + * Sets the number of epochs for MLP training. + * @param {Number} numEpochs + */ + setNumEpochs: function (numEpochs) { + this.modelSet.setNumEpochs(numEpochs); + }, + /** + * Returns the model set to its initial configuration. + * @returns {Boolean} true indicates successful initialization + */ + reset: function () { + return this.modelSet.reset(); + }, + /** + * Runs feed-forward regression on input + * @param {Array} input - An array of features to be processed. Non-arrays are converted. + * @returns {Array} output - One number for each model in the set + */ + run: function (input) { + //I'll assume that the args should have been an array + if (arguments.length > 1) { + input = Array.from(arguments); + } + //change input to vectors of doubles + let inputVector = new Module.VectorDouble(); + for (let i = 0; i < input.length; ++i) { + inputVector.push_back(input[i]); + } + //get the output + let outputVector = this.modelSet.run(inputVector); + //change back to javascript array + let output = []; + for (let i = 0; i < outputVector.size(); ++i) { + output.push(outputVector.get(i)); + } + return output; + }, + /** + * Deprecated! Use run() instead + * @param input + * @returns {Array} + */ + process: function (input) { + //return this.run(input); //Why doesn't this work? MZ + //I'll assume that the args should have been an array + if (arguments.length > 1) { + input = Array.from(arguments); + } + //change input to vectors of doubles + let inputVector = new Module.VectorDouble(); + for (let i = 0; i < input.length; ++i) { + inputVector.push_back(input[i]); + } + //get the output + let outputVector = new Module.VectorDouble(); + outputVector = this.modelSet.run(inputVector); + //change back to javascript array + let output = []; + for (let i = 0; i < outputVector.size(); ++i) { + output.push(outputVector.get(i)); + } + return output; + } +}; + +///////////////////////////////////////////////// Classification + +/** + * Creates a set of classification objects using the constructor from emscripten + * @constructor + * @property {function} Module.ClassificationCpp - constructor from emscripten + * @param {string} [type] - which classification algorithm to use + */ + +Module.Classification = function (type) { + if (type) { + this.modelSet = new Module.ClassificationCpp(type); + } else { + this.modelSet = new Module.ClassificationCpp(); + } +}; + +Module.Classification.prototype = { + /** + * Trains the models using the input. Clears previous training set. + * @param {Object} trainingSet - An array of training examples. + * @returns {Boolean} true indicates successful training + */ + train: function (trainingSet) { + this.modelSet.reset(); + return this.modelSet.train(Module.prepTrainingSet(trainingSet)); + }, + /** + * Returns a vector of current k values for each model. + * @returns {Array} k values + */ + getK: function () { + let outputVector = this.modelSet.getK(); + let output = []; + for (let i = 0; i < outputVector.size(); ++i) { + output.push(outputVector.get(i)); + } + return output; + }, + /** + * Sets the k values for a particular model model. + * @param {Number} whichModel - which model + * @param {Number} newK - set K to this value + */ + setK: function (whichModel, newK) { + this.modelSet.setK(whichModel, newK); + }, + /** + * Returns the model set to its initial configuration. + * @returns {Boolean} true indicates successful initialization + */ + reset: function () { + return this.modelSet.reset(); + }, + /** + * Does classifications on an input vector. + * @param {Array} input - An array of features to be processed. Non-arrays are converted. + * @returns {Array} output - One number for each model in the set + */ + run: function (input) { + //I'll assume that the args should have been an array + if (arguments.length > 1) { + input = Array.from(arguments); + } + //change input to vectors of doubles + let inputVector = new Module.VectorDouble(); + for (let i = 0; i < input.length; ++i) { + inputVector.push_back(input[i]); + } + //get the output + let outputVector = new Module.VectorDouble(); + outputVector = this.modelSet.run(inputVector); + //change back to javascript array + let output = []; + for (let i = 0; i < outputVector.size(); ++i) { + output.push(outputVector.get(i)); + } + return output; + }, + /** + * Deprecated! USe run() instead + * @param input + */ + process: function (input) { + //return this.run(input); //why doesn't this work? + //I'll assume that the args should have been an array + if (arguments.length > 1) { + input = Array.from(arguments); + } + //change input to vectors of doubles + let inputVector = new Module.VectorDouble(); + for (let i = 0; i < input.length; ++i) { + inputVector.push_back(input[i]); + } + //get the output + let outputVector = this.modelSet.run(inputVector); + //change back to javascript array + let output = []; + for (let i = 0; i < outputVector.size(); ++i) { + output.push(outputVector.get(i)); + } + return output; + } +}; + +////////////////////////////////////////////////// ModelSet + +/** + * Creates a set of machine learning objects using constructors from emscripten. Could be any mix of regression and classification. + * This is only useful when importing JSON from Wekinator. + * @constructor + */ +Module.ModelSet = function () { + this.myModelSet = []; + this.modelSet = new Module.ModelSetCpp(); +}; + +/** + * Creates a model set populated with models described in a JSON document. + * This only works in documents that are part of a CodeCircle document. + * @param {string} url - JSON loaded from a model set description document. + * @returns {Boolean} true indicates successful training + */ +Module.ModelSet.prototype = { + loadJSON: function (url) { + let that = this; + console.log('url ', url); + let request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "json"; + request.onload = function () { + let modelSet = this.response; + console.log("loaded: ", modelSet); + let allInputs = modelSet.metadata.inputNames; + modelSet.modelSet.forEach(function (value) { + let numInputs = value.numInputs; + let whichInputs = new Module.VectorInt(); + switch (value.modelType) { + case 'kNN classification': + let neighbours = new Module.TrainingSet(); + let k = value.k; + for (let i = 0; i < allInputs.length; ++i) { + if (value.inputNames.includes(allInputs[i])) { + whichInputs.push_back(i); + } + } + let myKnn = new Module.KnnClassification(numInputs, whichInputs, neighbours, k); + value.examples.forEach(function (value) { + let features = new Module.VectorDouble(); + for (let i = 0; i < numInputs; ++i) { + features.push_back(parseFloat(value.features[i])); + } + myKnn.addNeighbour(parseInt(value.class), features); + }); + that.addkNNModel(myKnn); + break; + case 'Neural Network': + let numLayers = value.numHiddenLayers; + let numNodes = value.numHiddenNodes; + let weights = new Module.VectorDouble(); + let wHiddenOutput = new Module.VectorDouble(); + let inRanges = new Module.VectorDouble(); + let inBases = new Module.VectorDouble(); + + let localWhichInputs = []; + for (let i = 0; i < allInputs.length; ++i) { + if (value.inputNames.includes(allInputs[i])) { + whichInputs.push_back(i); + localWhichInputs.push(i); + } + } + + let currentLayer = 0; + value.nodes.forEach(function (value, i) { + if (value.name === 'Linear Node 0') { //Output Node + for (let j = 1; j <= numNodes; ++j) { + let whichNode = 'Node ' + (j + (numNodes * (numLayers - 1))); + wHiddenOutput.push_back(parseFloat(value[whichNode])); + } + wHiddenOutput.push_back(parseFloat(value.Threshold)); + } else { + currentLayer = Math.floor((i - 1) / numNodes); //FIXME: This will break if node is out or order. + if (currentLayer < 1) { //Nodes connected to input + for (let j = 0; j < numInputs; ++j) { + weights.push_back(parseFloat(value['Attrib ' + allInputs[localWhichInputs[j]]])); + } + } else { //Hidden Layers + for (let j = 1; j <= numNodes; ++j) { + weights.push_back(parseFloat(value['Node ' + (j + (numNodes * (currentLayer - 1)))])); + } + } + weights.push_back(parseFloat(value.Threshold)); + } + }); + + for (let i = 0; i < numInputs; ++i) { + inRanges.push_back(value.inRanges[i]); + inBases.push_back(value.Bases[i]); + } + + let outRange = value.outRange; + let outBase = value.outBase; + + let myNN = new Module.NeuralNetwork(numInputs, whichInputs, numLayers, numNodes, weights, wHiddenOutput, inRanges, inBases, outRange, outBase); + that.addNNModel(myNN); + break; + default: + console.warn('unknown model type ', value.modelType); + break; + } + }); + }; + request.send(null); + return true; //TODO: make sure this is true; + }, + /** + * Add a NN model to a modelSet. //TODO: this doesn't need it's own function + * @param model + */ + addNNModel: function (model) { + console.log('Adding NN model'); + this.myModelSet.push(model); + }, + /** + * Add a kNN model to a modelSet. //TODO: this doesn't need it's own function + * @param model + */ + addkNNModel: function (model) { + console.log('Adding kNN model'); + this.myModelSet.push(model); + }, + /** + * Applies regression and classification algorithms to an input vector. + * @param {Array} input - An array of features to be processed. + * @returns {Array} output - One number for each model in the set + */ + run: function (input) { + let modelSetInput = new Module.VectorDouble(); + for (let i = 0; i < input.length; ++i) { + modelSetInput.push_back(input[i]); + } + let output = []; + for (let i = 0; i < this.myModelSet.length; ++i) { + output.push(this.myModelSet[i].run(modelSetInput)); + } + return output; + }, + /** + * Deprecated! Use run() instead. + * @param {Array} input - An array of features to be processed + * @returns {Array} output - One number for each model in the set + */ + process: function (input) { + return this.run(input); + } +}; + + +//////////////////////////////////////////////// + +/** + * Creates a series classification object using the constructor from emscripten + * @constructor + * @property {function} Module.SeriesClassificationCpp - constructor from emscripten + */ +Module.SeriesClassification = function () { + this.seriesClassification = new Module.SeriesClassificationCpp(); //TODO implement optional arguments +}; + +Module.SeriesClassification.prototype = { + /** + * Resets the model, and adds a set of series to be evaluated + * @param {Object} newSeriesSet - an array of objects, each with input: <array of arrays> and label: <string> + * @return {Boolean} True indicates successful training. + */ + train: function (newSeriesSet) { + this.reset(); + this.seriesClassification.train(Module.prepTrainingSeriesSet(newSeriesSet)); + return true; + }, + /** + * Returns the model set to its initial configuration. + * @returns {Boolean} true indicates successful initialization + */ + reset: function () { + return this.seriesClassification.reset(); + }, + /** + * Evaluates an input series and returns the index of the closet example + * @param {Object} inputSeries - an array of arrays + * @returns {Number} The index of the closest matching series + */ + run: function (inputSeries, label) { + let vecInputSeries = new Module.VectorVectorDouble(); + for (let i = 0; i < inputSeries.length; ++i) { + let tempVector = new Module.VectorDouble(); + for (let j = 0; j < inputSeries[i].length; ++j) { + tempVector.push_back(inputSeries[i][j]); + } + vecInputSeries.push_back(tempVector); + } + if (arguments.length > 1) { + return this.seriesClassification.runLabel(vecInputSeries, label); + } else { + return this.seriesClassification.run(vecInputSeries); + } + }, + /** + * Deprecated! Use run() + * @param inputSeries + * @returns {Number} + */ + process: function (inputSeries) { + return this.run(inputSeries); + }, + /** + * Returns an array of costs to match the input series to each example series. A lower cost is a closer match + * @returns {Array} + */ + getCosts: function () { + let returnArray = []; + let VecDouble = this.seriesClassification.getCosts(); + for (let i = 0; i < VecDouble.size(); ++i) { + returnArray[i] = VecDouble.get(i); + } + return returnArray; + } +}; + +///////////////////////////////////////////////// + +/** + * Creates a circular buffer that can return various statistics + * @constructor + * @param {number} [windowSize=3] - specify the size of the buffer + * @property {function} Module.rapidStreamCpp - constructor from emscripten + */ + +Module.StreamBuffer = function (windowSize) { + if (windowSize) { + this.rapidStream = new Module.RapidStreamCpp(windowSize); + } else { + this.rapidStream = new Module.RapidStreamCpp(); + } +}; + +Module.StreamBuffer.prototype = { + /** + * Add a value to a circular buffer whose size is defined at creation. + * @param {number} input - value to be pushed into circular buffer. + */ + push: function (input) { + this.rapidStream.pushToWindow(parseFloat(input)); + }, + /** + * Resets all the values in the buffer to zero. + */ + reset: function () { + this.rapidStream.clear(); + }, + /** + * Calculate the first-order difference (aka velocity) between the last two inputs. + * @return {number} difference between last two inputs. + */ + velocity: function () { + return this.rapidStream.velocity(); + }, + /** + * Calculate the second-order difference (aka acceleration) over the last three inputs. + * @return {number} acceleration over the last three inputs. + */ + acceleration: function () { + return this.rapidStream.acceleration(); + }, + /** + * Find the minimum value in the buffer. + * @return {number} minimum. + */ + minimum: function () { + return this.rapidStream.minimum(); + }, + /** + * Find the maximum value in the buffer. + * @return {number} maximum. + */ + maximum: function () { + return this.rapidStream.maximum(); + }, + /** + * Calculate the sum of all values in the buffer. + * @return {number} sum. + */ + sum: function () { + return this.rapidStream.sum(); + }, + /** + * Calculate the mean of all values in the buffer. + * @return {number} mean. + */ + mean: function () { + return this.rapidStream.mean(); + }, + /** + * Calculate the standard deviation of all values in the buffer. + * @return {number} standard deviation. + */ + standardDeviation: function () { + return this.rapidStream.standardDeviation(); + }, + /** + * Calculate the root mean square of the values in the buffer + * @return {number} rms + */ + rms: function () { + return this.rapidStream.rms(); + }, + /** + * Calculate the minimum first-order difference over consecutive inputs in the buffer. + * @return {number} minimum velocity. + */ + minVelocity: function () { + return this.rapidStream.minVelocity(); + }, + /** + * Calculate the maximum first-order difference over consecutive inputs in the buffer. + * @return {number} maximum velocity. + */ + maxVelocity: function () { + return this.rapidStream.maxVelocity(); + }, + /** + * Calculate the minimum second-order difference over consecutive inputs in the buffer. + * @return {number} minimum acceleration. + */ + minAcceleration: function () { + return this.rapidStream.minAcceleration(); + }, + /** + * Calculate the maximum second-order difference over consecutive inputs in the buffer. + * @return {number} maximum acceleration. + */ + maxAcceleration: function () { + return this.rapidStream.maxAcceleration(); + } +}; \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/rapidStreamEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/rapidStreamEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..55c750952d706db93c8b4154334da09c43016535 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/rapidStreamEmbindings.h @@ -0,0 +1,38 @@ +// +// rapidStreamEmbindings.h +// RapidLib +// +// Created by mzed on 01/06/2017. +// Copyright © 2017 Goldsmiths. All rights reserved. +// + +#ifndef rapidStreamEmbindings_h +#define rapidStreamEmbindings_h + +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(rapidStream_module) { + class_<rapidStream<double> >("RapidStreamCpp") //name change so that I can wrap it in Javascript. -mz + .constructor() + .constructor<int>() + .function("clear", &rapidStream<double>::clear) + .function("pushToWindow", &rapidStream<double>::pushToWindow) + .function("velocity", &rapidStream<double>::velocity) + .function("acceleration", &rapidStream<double>::acceleration) + .function("minimum", &rapidStream<double>::minimum) + .function("maximum", &rapidStream<double>::maximum) + .function("sum", &rapidStream<double>::sum) + .function("mean", &rapidStream<double>::mean) + .function("standardDeviation", &rapidStream<double>::standardDeviation) + .function("rms", &rapidStream<double>::rms) + .function("minVelocity", &rapidStream<double>::minVelocity) + .function("maxVelocity", &rapidStream<double>::maxVelocity) + .function("minAcceleration", &rapidStream<double>::minAcceleration) + .function("maxAcceleration", &rapidStream<double>::maxAcceleration) + ; + +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/regressionEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/regressionEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..7c40b709d297e5fc93d2fa47f44583d542f52d2c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/regressionEmbindings.h @@ -0,0 +1,29 @@ +// +// regressionEmbindings.cpp +// RapidLib +// +// Created by mzed on 26/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef regressionEmbindings_h +#define regressionEmbindings_h + +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(regression_module) { + class_<regressionTemplate<double>, base<modelSet<double> > >("RegressionCpp") //name change so that I can wrap it in Javascript. -mz + .constructor() + .constructor< std::vector<trainingExampleTemplate<double> > >() + .constructor<int, int>() + .function("train", ®ressionTemplate<double>::train) + .function("getNumHiddenLayers", ®ressionTemplate<double>::getNumHiddenLayers) + .function("setNumHiddenLayers", ®ressionTemplate<double>::setNumHiddenLayers) + .function("setNumEpochs", ®ressionTemplate<double>::setNumEpochs) + ; + +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/seriesClassificationEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/seriesClassificationEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..c6108053ec8a0148812c33f9d67451835095f924 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/seriesClassificationEmbindings.h @@ -0,0 +1,28 @@ +// +// seriesClassification.h +// RapidLib +// +// Created by mzed on 13/06/2017. +// Copyright © 2017 Goldsmiths. All rights reserved. +// + + +#ifndef seriesClassificationEmbindings_h +#define seriesClassificationEmbindings_h + +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(seriesClassification_module) { + class_<seriesClassificationTemplate<double> >("SeriesClassificationCpp") //name change so that I can wrap it in Javascript. -mz + .constructor() + .function("reset", &seriesClassificationTemplate<double>::reset) + .function("train", &seriesClassificationTemplate<double>::train) + .function("run", select_overload<std::string(const std::vector<std::vector<double>>&)>(&seriesClassificationTemplate<double>::run)) + .function("runLabel", select_overload<double(const std::vector<std::vector<double>>&, std::string)>(&seriesClassificationTemplate<double>::run)) + .function("getCosts", &seriesClassificationTemplate<double>::getCosts) + ; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/svmEmbindings.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/svmEmbindings.h new file mode 100644 index 0000000000000000000000000000000000000000..f867ce26a71bef7bffe762fce0abcbd3c30fddf5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/emscripten/svmEmbindings.h @@ -0,0 +1,26 @@ +// +// svmEmbindings.cpp +// RapidLib +// +// Created by mzed on 25/08/2017. +// Copyright © 2017 Goldsmiths. All rights reserved. +// + + +#ifndef svmEmbindings_h +#define svmEmbindings_h + +#include <vector> +#include <emscripten/bind.h> + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(svm_module) { + class_<svmClassification<double>>("svmClassificationCPP") + .constructor<int>() + .function("train", &svmClassification<double>::train) + .function("run", &svmClassification<double>::run) + ; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/fastDTW.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/fastDTW.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbc4ed73afa80fcc3cf26466783b2b54c9370beb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/fastDTW.cpp @@ -0,0 +1,75 @@ +/** + * @file fastDTW.cpp + * RapidLib + * + * @author Michael Zbyszynski + * @date 07 Sep 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include "fastDTW.h" +#include "dtw.h" + +template<typename T> +fastDTW<T>::fastDTW() {}; + +template<typename T> +fastDTW<T>::~fastDTW() {}; + +template<typename T> +warpInfo fastDTW<T>::fullFastDTW(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY, int searchRadius){ + +#ifndef EMSCRIPTEN + if (seriesY.size() > seriesX.size()) { + return fullFastDTW(seriesY, seriesX, searchRadius); //TODO: I'm not sure why I need this. Also, not sure why it fails with Emscripten. + } +#endif + + dtw<T> dtw; + searchRadius = (searchRadius < 0) ? 0 : searchRadius; + int minSeries = searchRadius + 2; + if (seriesX.size() <= minSeries || seriesY.size() <= minSeries) { + return dtw.dynamicTimeWarp(seriesX, seriesY); + } + + T resolution = 2.0;//TODO: Just hardcode this? + std::vector<std::vector<T>> shrunkenX = downsample(seriesX, resolution); + std::vector<std::vector<T>> shrunkenY = downsample(seriesY, resolution); + + //some nice recursion here + searchWindow<T> window(int(seriesX.size()), int(seriesY.size()), getWarpPath(shrunkenX, shrunkenY, searchRadius), searchRadius); + return dtw.constrainedDTW(seriesX, seriesY, window); +}; + +template<typename T> +T fastDTW<T>::getCost(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY, int searchRadius){ + warpInfo info = fullFastDTW(seriesX, seriesY, searchRadius); + return info.cost; +}; + +template<typename T> +warpPath fastDTW<T>::getWarpPath(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY, int searchRadius){ + warpInfo info = fullFastDTW(seriesX, seriesY, searchRadius); + return info.path; +}; + +template<typename T> +std::vector<std::vector<T> > fastDTW<T>::downsample(const std::vector<std::vector<T>> &series, T resolution) { + std::vector<std::vector<T> > shrunkenSeries; + for (int i = 0; i < series.size(); ++i) { + if (i % 2 == 0) { + shrunkenSeries.push_back(series[i]); + } else { + int shrunkIndex = int(i/2); + for (int j = 0; j < series[i].size(); ++j) { + shrunkenSeries[shrunkIndex][j] = (shrunkenSeries[shrunkIndex][j] + series[i][j]) / 2; + } + } + } + //TODO: implement downsampling by resolution + return shrunkenSeries; +} + +//explicit instantiation +template class fastDTW<double>; +template class fastDTW<float>; \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/fastDTW.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/fastDTW.h new file mode 100644 index 0000000000000000000000000000000000000000..654e165439d94a8401059d456c0a30a9d18355d2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/fastDTW.h @@ -0,0 +1,61 @@ +/** + * @file fastDTW.h + * RapidLib + * @author Michael Zbyszynski + * @date 07 Sep 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef fastDTW_h +#define fastDTW_h + +#include <vector> +#include "warpPath.h" + +/** Class for performing an fast dynamic time warping between two time series*/ +template<typename T> +class fastDTW { +public: + fastDTW(); + ~fastDTW(); + + /** + * Returns just the cost of warping one series into a second. + * @param seriesX time series X + * @param seriesY time series Y + * @param searchRadius search radius (usually 1) + * @return cost to warp between series + */ + static T getCost(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY, int searchRadius); + +private: + /** + * Returns the cost and the warp path. + * @param seriesX time series X + * @param seriesY time series Y + * @param searchRadius search radius (usually 1) + * @return information about optimal time warp + */ + static warpInfo fullFastDTW(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY, int searchRadius); + + /** + * Returns just lowest cost path to warping one series into a second. + * @param seriesX time series X + * @param seriesY time series Y + * @param searchRadius search radius (usually 1) + * @return The warp path + */ + static warpPath getWarpPath(const std::vector<std::vector<T>> &seriesX, const std::vector<std::vector<T > > &seriesY, int searchRadius); + + /** + * Downsamples a time series by two. Resolution isn't implemented yet + * @param series + * @param resolution (not used) + * @return downsampled series + `*/ + static std::vector<std::vector<T> > downsample(const std::vector<std::vector<T>> &series, T resolution); + +}; + + +#endif /* fastDTW_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/knnClassification.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/knnClassification.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f470b4af4619a84be1bd7dc54a75935a7694c2e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/knnClassification.cpp @@ -0,0 +1,171 @@ +// +// knnClassification.cpp +// RapidLib +// +// Created by mzed on 05/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#include <cmath> +#include <utility> +#include <map> +#include <vector> +#include <algorithm> +#include "knnClassification.h" +#ifdef EMSCRIPTEN +#include "emscripten/knnEmbindings.h" +#endif + +template<typename T> +knnClassification<T>::knnClassification(const int &num_inputs, const std::vector<int> &which_inputs, const std::vector<trainingExampleTemplate<T> > &_neighbours, const int k) +: numInputs(num_inputs), +whichInputs(which_inputs), +neighbours(_neighbours), +desiredK(k), +currentK(k) +{ + nearestNeighbours = new std::pair<int, T>[currentK]; +} + +template<typename T> +knnClassification<T>::~knnClassification() { + delete[] nearestNeighbours; +} + +template<typename T> +void knnClassification<T>::reset() { + //TODO: implement this +} + +template<typename T> +int knnClassification<T>::getNumInputs() const { + return numInputs; +} + +template<typename T> +std::vector<int> knnClassification<T>::getWhichInputs() const { + return whichInputs; +} + +template<typename T> +int knnClassification<T>::getK() const { + return currentK; +} + +template<typename T> +inline void knnClassification<T>::updateK() { + if (currentK != desiredK) { + currentK = std::min(desiredK, (int) neighbours.size()); + } +} + +template<typename T> +void knnClassification<T>::setK(int newK) { + desiredK = newK; + updateK(); +} + +template<typename T> +void knnClassification<T>::addNeighbour(const int &classNum, const std::vector<T> &features) { + std::vector<T> classVec; + classVec.push_back(T(classNum)); + trainingExampleTemplate<T> newNeighbour = {features, classVec}; + neighbours.push_back(newNeighbour); + updateK(); +}; + +template<typename T> +void knnClassification<T>::train(const std::vector<trainingExampleTemplate<T> > &trainingSet) { //FIXME: Does numInputs need to be reset here? -MZ + neighbours.clear(); + neighbours = trainingSet; + updateK(); +}; + +template<typename T> +T knnClassification<T>::run(const std::vector<T> &inputVector) { + for (int i = 0; i < currentK; ++i) { + nearestNeighbours[i] = {0, 0.}; + }; + std::pair<int, T> farthestNN = {0, 0.}; + + std::vector<T> pattern; + for (int h = 0; h < numInputs; h++) { + pattern.push_back(inputVector[whichInputs[h]]); + } + + //Find k nearest neighbours + int index = 0; + for (typename std::vector<trainingExampleTemplate<T> >::iterator it = neighbours.begin(); it != neighbours.end(); ++it) { + //find Euclidian distance for this neighbor + T euclidianDistance = 0; + for(int j = 0; j < numInputs ; ++j){ + euclidianDistance += pow((pattern[j] - it->input[j]), 2); + } + euclidianDistance = sqrt(euclidianDistance); + if (index < currentK) { + //save the first k neighbours + nearestNeighbours[index] = {index, euclidianDistance}; + if (euclidianDistance > farthestNN.second) { + farthestNN = {index, euclidianDistance}; + } + } else if (euclidianDistance < farthestNN.second) { + //replace farthest, if new neighbour is closer + nearestNeighbours[farthestNN.first] = {index, euclidianDistance}; + int currentFarthest = 0; + T currentFarthestDistance = 0.; + for (int n = 0; n < currentK; n++) { + if (nearestNeighbours[n].second > currentFarthestDistance) { + currentFarthest = n; + currentFarthestDistance = nearestNeighbours[n].second; + } + } + farthestNN = {currentFarthest, currentFarthestDistance}; + } + ++index; + } + + //majority vote on nearest neighbours + std::map<int, int> classVoteMap; + typedef std::pair<int, int> classVotePair; + for (int i = 0; i < currentK; ++i){ + int classNum = (int) std::round(neighbours[nearestNeighbours[i].first].output[0]); + if ( classVoteMap.find(classNum) == classVoteMap.end() ) { + classVoteMap.insert(classVotePair(classNum, 1)); + } else { + classVoteMap[classNum]++; + } + } + T foundClass = 0; + int mostVotes = 0; + std::map<int, int>::iterator p; + for(p = classVoteMap.begin(); p != classVoteMap.end(); ++p) + { + if (p->second > mostVotes) { + mostVotes = p->second; + foundClass = p->first; + } + } + return foundClass; +} + +#ifndef EMSCRIPTEN +template<typename T> +void knnClassification<T>::getJSONDescription(Json::Value &jsonModelDescription) { + jsonModelDescription["modelType"] = "kNN Classificiation"; + jsonModelDescription["numInputs"] = numInputs; + jsonModelDescription["whichInputs"] = this->vector2json(whichInputs); + jsonModelDescription["k"] = desiredK; + Json::Value examples; + for (typename std::vector<trainingExampleTemplate<T> >::iterator it = neighbours.begin(); it != neighbours.end(); ++it) { + Json::Value oneExample; + oneExample["class"] = it->output[0]; + oneExample["features"] = this->vector2json(it->input); + examples.append(oneExample); + } + jsonModelDescription["examples"] = examples; +} +#endif + +//explicit instantiation +template class knnClassification<double>; +template class knnClassification<float>; diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/knnClassification.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/knnClassification.h new file mode 100644 index 0000000000000000000000000000000000000000..8c2b8fb5aab14ef7373165ee195b079971091935 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/knnClassification.h @@ -0,0 +1,93 @@ +// +// knnClassification.h +// RapidLib +// +// Created by mzed on 05/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef knnClassification_h +#define knnClassification_h + +#include <vector> +#include "baseModel.h" + +#ifndef EMSCRIPTEN +#include "../dependencies/json/json.h" +#endif + +/** Class for implementing a knn classifier */ +template<typename T> +class knnClassification : public baseModel<T> { + +public: + /** Constructor that takes training examples in + * @param number of inputs expected in the training and input vectors + * @param vector of input numbers to be fed into the classifer. + * @param vector of training examples + * @param how many near neighbours to evaluate + */ + knnClassification(const int &num_inputs, + const std::vector<int> &which_inputs, + const std::vector<trainingExampleTemplate<T> > &trainingSet, + const int k); + ~knnClassification(); + + /** add another example to the existing training set + * @param class number of example + * @param feature vector of example + */ + void addNeighbour(const int &classNum, const std::vector<T> &features); + + /** Generate an output value from a single input vector. + * @param A standard vector of type T to be evaluated. + * @return A single value of type T: the nearest class as determined by k-nearest neighbor. + */ + T run(const std::vector<T> &inputVector); + + /** Fill the model with a vector of examples. + * + * @param The training set is a vector of training examples that contain both a vector of input values and a value specifying desired output class. + * + */ + void train(const std::vector<trainingExampleTemplate<T> > &trainingSet); + + /** Reset the model to its empty state. */ + void reset(); + + /** Find out how many inputs the model expects + * @return Integer number of intpus + */ + int getNumInputs() const; + + /** Find out which inputs in a vector will be used + * @return Vector of ints, specifying input indices. + */ + std::vector<int> getWhichInputs() const; + + /** Get the number of nearest neighbours used by the kNN algorithm. */ + int getK() const; + /** Change the number of nearest neighbours used by the kNN algorithm. + * @param new value for k + */ + void setK(int newK); + +#ifndef EMSCRIPTEN + /** Populate a JSON value with a description of the current model + * @param A JSON value to be populated + */ + void getJSONDescription(Json::Value ¤tModel); +#endif + +private: + int numInputs; + std::vector<int> whichInputs; + std::vector<trainingExampleTemplate<T>> neighbours; + int desiredK; //K that user asked for might be limited but number of examples + int currentK; //K minimum of desiredK or neighbours.size() + inline void updateK(); + std::pair<int, T>* nearestNeighbours; +}; + +#endif + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/modelSet.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/modelSet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..20c1a942cafbce9c2a9822ca1ddcdb961c0bfd3f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/modelSet.cpp @@ -0,0 +1,242 @@ +// +// modelSet.cpp +// RapidLib +// +// Created by mzed on 26/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + + +#include <fstream> +#include <vector> +#include <cmath> +#include <algorithm> +#include "modelSet.h" + +#ifndef EMSCRIPTEN +#include "../dependencies/json/json.h" +#else +#include "emscripten/modelSetEmbindings.h" +#endif + +/** No arguments, don't create any models yet */ +template<typename T> +modelSet<T>::modelSet() : +numInputs(0), +numOutputs(0), +created(false) +{ +}; + +template<typename T> +modelSet<T>::~modelSet() { + for (typename std::vector<baseModel<T>*>::iterator i = myModelSet.begin(); i != myModelSet.end(); ++i) { + delete *i; + } +}; + +template<typename T> +bool modelSet<T>::train(const std::vector<trainingExampleTemplate<T> > &training_set) { + for (trainingExampleTemplate<T> example : training_set) { + if (example.input.size() != numInputs) { + return false; + } + if (example.output.size() != numOutputs) { + return false; + } + } + for (int i = 0; i < myModelSet.size(); ++i) { + std::vector<trainingExampleTemplate<T> > modelTrainingSet; //just one output + for (trainingExampleTemplate<T> example : training_set) { + std::vector<T> tempT; + for (int j = 0; j < numInputs; ++j) { + tempT.push_back(example.input[j]); + } + trainingExampleTemplate<T> tempObj = {tempT, std::vector<T> {example.output[i]}}; + modelTrainingSet.push_back(tempObj); + } + myModelSet[i]->train(modelTrainingSet); + } + created = true; + return true; +} + +template<typename T> +bool modelSet<T>::reset() { + for (typename std::vector<baseModel<T>*>::iterator i = myModelSet.begin(); i != myModelSet.end(); ++i) { + delete *i; + } + myModelSet.clear(); + numInputs = 0; + numOutputs = 0; + created = false; + return true; +} + +template<typename T> +std::vector<T> modelSet<T>::run(const std::vector<T> &inputVector) { + std::vector<T> returnVector; + if (created && inputVector.size() == numInputs) { + for (auto model : myModelSet) { + returnVector.push_back(model->run(inputVector)); + } + } else { + returnVector.push_back(0); + } + return returnVector; +} + + + +#ifndef EMSCRIPTEN +//In emscripten, we do the JSON parsing with native JavaScript +template<typename T> +std::vector<T> json2vector(Json::Value json) { + std::vector<T> returnVec; + for (unsigned int i = 0; i < json.size(); ++i) { + returnVec.push_back(json[i].asDouble()); + } + return returnVec; +} + +template<typename T> +Json::Value modelSet<T>::parse2json() { + Json::Value root; + Json::Value metadata; + Json::Value modelSet; + + metadata["creator"] = "Rapid API C++"; + metadata["version"] = "v0.1.1"; //TODO: This should be a macro someplace + metadata["numInputs"] = numInputs; + Json::Value inputNamesJSON; + for (int i = 0; i < inputNames.size(); ++i) { + inputNamesJSON.append(inputNames[i]); + } + metadata["inputNames"] = inputNamesJSON; + metadata["numOutputs"] = numOutputs; + root["metadata"] = metadata; + for (auto model : myModelSet) { + Json::Value currentModel; + currentModel["inputNames"] = inputNamesJSON; //TODO: implment this feature + model->getJSONDescription(currentModel); + modelSet.append(currentModel); + } + root["modelSet"] = modelSet; + return root; +} + +template<typename T> +std::string modelSet<T>::getJSON() { + Json::Value root = parse2json(); + return root.toStyledString(); +} + +template<typename T> +void modelSet<T>::writeJSON(const std::string &filepath) { + Json::Value root = parse2json(); + std::ofstream jsonOut; + jsonOut.open (filepath); + Json::StyledStreamWriter writer; + writer.write(jsonOut, root); + jsonOut.close(); + +} + +template<typename T> +bool modelSet<T>::putJSON(const std::string &jsonMessage) { + Json::Value parsedFromString; + Json::Reader reader; + bool parsingSuccessful = reader.parse(jsonMessage, parsedFromString); + if (parsingSuccessful) + { + json2modelSet(parsedFromString); + } + return parsingSuccessful; +} + +template<typename T> +void modelSet<T>::json2modelSet(const Json::Value &root) { + numInputs = root["metadata"]["numInputs"].asInt(); + for (unsigned int i = 0; i < root["metadata"]["inputNames"].size(); ++i) { + inputNames.push_back(root["metadata"]["inputNames"][i].asString()); + } + numOutputs = root["metadata"]["numOutputs"].asInt(); + + for (const Json::Value& model : root["modelSet"]) { + int modelNumInputs = model["numInputs"].asInt(); + std::vector<int> whichInputs; + std::vector<std::string> modelInputNames; + for (unsigned int i = 0; i < model["inputNames"].size(); ++i) { + modelInputNames.push_back(model["inputNames"][i].asString()); + } + for (int i = 0; i < inputNames.size(); ++i) { + if (std::find(modelInputNames.begin(), modelInputNames.end(), inputNames[i]) != modelInputNames.end()) + { + whichInputs.push_back(i); + } + } + if (model["modelType"].asString() == "Neural Network") { + int numHiddenLayers = model["numHiddenLayers"].asInt(); + int numHiddenNodes = model["numHiddenNodes"].asInt(); + std::vector<T> weights; + std::vector<T> wHiddenOutput; + int nodeIndex = 0; + for (const Json::Value& node : model["nodes"]) { + if (node["name"].asString() == "Linear Node 0") { + for (int i = 1; i <= numHiddenNodes; ++i) { + std::string whichNode = "Node " + std::to_string(i + (numHiddenNodes * (numHiddenLayers - 1))); + wHiddenOutput.push_back(node[whichNode].asDouble()); + } + wHiddenOutput.push_back(node["Threshold"].asDouble()); + } else { //FIXME: this will break if nodes are out of order + int currentLayer = (int) floor((nodeIndex - 1.0)/ (double)numHiddenNodes); + if (currentLayer < 1) { //Nodes connected to input + for (int i = 0; i < numInputs; ++i) { + std::string whichNode = "Attrib " + model["inputNames"][i].asString(); + weights.push_back(node[whichNode].asDouble()); + } + } else { //Hidden Layers + for (int i = 0; i < numHiddenNodes; ++i) { + std::string whichNode = "Node " + std::to_string(i + (numHiddenNodes * (currentLayer - 1))); + weights.push_back(node[whichNode].asDouble()); + } } + weights.push_back(node["Threshold"].asDouble()); + } + nodeIndex++; + } + std::vector<T> inBases = json2vector<T>(model["inBases"]); + std::vector<T> inRanges = json2vector<T>(model["inRanges"]); + T outRange = model["outRange"].asDouble(); + T outBase = model["outBase"].asDouble(); + + myModelSet.push_back(new neuralNetwork<T>(modelNumInputs, whichInputs, numHiddenLayers, numHiddenNodes, weights, wHiddenOutput, inRanges, inBases, outRange, outBase)); + } else if (model["modelType"].asString() == "kNN Classificiation") { + std::vector<trainingExampleTemplate<T> > trainingSet; + const Json::Value examples = model["examples"]; + for (unsigned int i = 0; i < examples.size(); ++i) { + trainingExampleTemplate<T> tempExample; + tempExample.input = json2vector<T>(examples[i]["features"]); + tempExample.output.push_back(examples[i]["class"].asDouble()); + trainingSet.push_back(tempExample); + } + int k = model["k"].asInt(); + myModelSet.push_back(new knnClassification<T>(modelNumInputs, whichInputs, trainingSet, k)); + } + } + created = true; +} + +template<typename T> +bool modelSet<T>::readJSON(const std::string &filepath) { + Json::Value root; + std::ifstream file(filepath); + file >> root; + json2modelSet(root); + return created; //TODO: check something first +} +#endif + +//explicit instantiation +template class modelSet<double>; +template class modelSet<float>; + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/modelSet.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/modelSet.h new file mode 100644 index 0000000000000000000000000000000000000000..53be912c81b234ae101a76b71aa218a7371fe82c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/modelSet.h @@ -0,0 +1,60 @@ +// +// modelSet.h +// RapidLib +// +// Created by mzed on 26/09/2016. +// Copyright © 2016 Goldsmiths. All rights reserved. +// + +#ifndef modelSet_h +#define modelSet_h + +#include <vector> +#include "trainingExample.h" +#include "baseModel.h" +#include "neuralNetwork.h" +#include "knnClassification.h" +#include "svmClassification.h" +#ifndef EMSCRIPTEN +#include "../dependencies/json/json.h" +#endif + +/** This class holds a set of models with the same or different algorithms. */ +template<typename T> +class modelSet { +public: + modelSet(); + virtual ~modelSet(); + /** Train on a specified set, causes creation if not created */ + virtual bool train(const std::vector<trainingExampleTemplate<T> > &trainingSet); + /** reset to pre-training state */ + bool reset(); + /** run regression or classification for each model */ + std::vector<T> run(const std::vector<T> &inputVector); + +protected: + std::vector<baseModel<T>*> myModelSet; + int numInputs; + std::vector<std::string> inputNames; + int numOutputs; + bool created; + +#ifndef EMSCRIPTEN //The javascript code will do its own JSON parsing +public: + /** Get a JSON representation of the model in the form of a styled string */ + std::string getJSON(); + /** Write a JSON model description to specified file path */ + void writeJSON(const std::string &filepath); + /** configure empty model with string. See getJSON() */ + bool putJSON(const std::string &jsonMessage); + /** read a JSON file at file path and build a modelSet from it */ + bool readJSON(const std::string &filepath); + +private: + Json::Value parse2json(); + void json2modelSet(const Json::Value &root); + +#endif +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/neuralNetwork.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/neuralNetwork.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3b2f88b964579cf72a5d1a9f71f06250caf2db1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/neuralNetwork.cpp @@ -0,0 +1,448 @@ +/** + * @file neuralNetwork.cpp + * RapidLib + * + * @date 05 Sep 2016 + * @copyright Copyright © 2016 Goldsmiths. All rights reserved. + */ + +#include <math.h> +#include <random> +#include <algorithm> +#include <vector> + +#include "neuralNetwork.h" +#ifdef EMSCRIPTEN +#include "emscripten/nnEmbindings.h" +#endif + +template<typename T> +void neuralNetwork<T>::initTrainer() { + //initialize deltas + deltaWeights = std::vector<std::vector<std::vector<T> > >(numHiddenLayers, std::vector<std::vector<T> >(numHiddenNodes, std::vector<T>((numInputs + 1), 0))); + deltaHiddenOutput = std::vector<T>((numHiddenNodes + 1), 0); +} + +/*! + * This is the constructor for a model imported from JSON. + */ +template<typename T> +neuralNetwork<T>::neuralNetwork(const int &num_inputs, + const std::vector<int> &which_inputs, + const int &num_hidden_layers, + const int &num_hidden_nodes, + const std::vector<T> &_weights, + const std::vector<T> &w_hidden_output, + const std::vector<T> &in_ranges, + const std::vector<T> &in_bases, + const T &out_range, + const T &out_base + ) +: +numInputs(num_inputs), +whichInputs(which_inputs), +numHiddenLayers(num_hidden_layers), +numHiddenNodes(num_hidden_nodes), +wHiddenOutput(w_hidden_output), +inRanges(in_ranges), +inBases(in_bases), +outRange(out_range), +outBase(out_base), +learningRate(LEARNING_RATE), +momentum(MOMENTUM), +numEpochs(NUM_EPOCHS), +outputErrorGradient(0) +{ + bool randomize = _weights.size() ? false : true; + std::default_random_engine generator; + std::uniform_real_distribution<T> distribution(-0.5,0.5); + //winding up a long vector from javascript + int count = 0; + for (int i = 0; i < numHiddenLayers; ++i) { + std::vector<std::vector<T>> layer; + for (int j = 0; j < numHiddenNodes; ++j){ + std::vector<T> node; + int numConnections = (i == 0) ? numInputs : numHiddenNodes; + for(int k = 0; k <= numConnections; ++k){ + if (randomize) { + node.push_back(distribution(generator)); + } else { + node.push_back( _weights[count]); + } + count++; + } + layer.push_back(node); + } + weights.push_back(layer); + } + + if (randomize) { + for (int i = 0; i <= numHiddenNodes; ++i) { + wHiddenOutput.push_back(distribution(generator)); + } + } + + for (int i = 0; i < inRanges.size(); ++i) { + if (inRanges[i] == 0.) { + inRanges[i] = 1.0; //Prevent divide by zero later. + } + } + + //trainer -- do we really need this? + initTrainer(); +} + + + +/*! + * This is the constructor for a model that needs to be trained. + */ +template<typename T> +neuralNetwork<T>::neuralNetwork(const int &num_inputs, + const std::vector<int> &which_inputs, + const int &num_hidden_layers, + const int &num_hidden_nodes + ) +: +numInputs(num_inputs), +whichInputs(which_inputs), +numHiddenLayers(num_hidden_layers), +numHiddenNodes(num_hidden_nodes), +learningRate(LEARNING_RATE), +momentum(MOMENTUM), +numEpochs(NUM_EPOCHS), +outputErrorGradient(0) +{ + //randomize weights + reset(); + + //trainer + initTrainer(); +} + +/*! + * This destructor is not needed. + */ +template<typename T> +neuralNetwork<T>::~neuralNetwork() { +} + +template<typename T> +void neuralNetwork<T>::reset() { + std::default_random_engine generator; + std::uniform_real_distribution<T> distribution(-0.5,0.5); + + weights.clear(); + for (int i = 0; i < numHiddenLayers; ++i) { + std::vector<std::vector<T>> layer; + for (int j = 0; j < numHiddenNodes; ++j){ + std::vector<T> node; + int numConnections = (i == 0) ? numInputs : numHiddenNodes; + for(int k = 0; k <= numConnections; ++k){ + node.push_back(distribution(generator)); + } + layer.push_back(node); + } + weights.push_back(layer); + } + + wHiddenOutput.clear(); + for (int i = 0; i <= numHiddenNodes; ++i) { + wHiddenOutput.push_back(distribution(generator)); + } +} + +template<typename T> +inline T neuralNetwork<T>::getHiddenErrorGradient(int layer, int neuron) { + T weightedSum = 0; + if (numHiddenLayers == 1 || layer == 0) { + T wGradient = wHiddenOutput[neuron] * outputErrorGradient; + return hiddenNeurons[layer][neuron] * (1 - hiddenNeurons[layer][neuron]) * wGradient; + } + if (layer == numHiddenLayers - 1) { + for (int i = 0; i < numHiddenNodes; ++i) { + weightedSum += wHiddenOutput[i] * outputErrorGradient; + } + } else { + for (int i = 0; i < numHiddenNodes; ++i) { + weightedSum += deltaWeights[layer +1][neuron][i] * outputErrorGradient; + } + } + return hiddenNeurons[layer][neuron] * (1 - hiddenNeurons[layer][neuron]) * weightedSum; +} + +template<typename T> +inline T neuralNetwork<T>::activationFunction(T x) { + //sigmoid + if (x < -45) { //from weka, to combat overflow + x = 0; + } else if (x > 45) { + x = 1; + } else { + x = 1/(1 + exp(-x)); + } + return x; +} + +template<typename T> +int neuralNetwork<T>::getNumInputs() const { + return numInputs; +} + +template<typename T> +std::vector<int> neuralNetwork<T>::getWhichInputs() const { + return whichInputs; +} +template<typename T> +int neuralNetwork<T>::getNumHiddenLayers() const { + return numHiddenLayers; +} + +template<typename T> +void neuralNetwork<T>::setNumHiddenLayers(int num_hidden_layers) { + numHiddenLayers = num_hidden_layers; + reset(); + initTrainer(); +} + +template<typename T> +int neuralNetwork<T>::getNumHiddenNodes() const { + return numHiddenNodes; +} + +template<typename T> +void neuralNetwork<T>::setEpochs(const int &epochs) { + numEpochs = epochs; +} + +template<typename T> +std::vector<T> neuralNetwork<T>::getWeights() const{ + std::vector<T> flatWeights; + for (int i = 0; i < weights.size(); ++i) { + for (int j = 0; j < weights[i].size(); ++j) { + for (int k = 0; k < weights[i][j].size(); ++k) { + flatWeights.push_back(weights[i][j][k]); + } + } + } + return flatWeights; +} + +template<typename T> +std::vector<T> neuralNetwork<T>::getWHiddenOutput() const { + return wHiddenOutput; +} + +template<typename T> +std::vector<T> neuralNetwork<T>::getInRanges() const { + return inRanges; +} + +template<typename T> +std::vector<T> neuralNetwork<T>::getInBases() const { + return inBases; +} + +template<typename T> +T neuralNetwork<T>::getOutRange() const { + return outRange; +} + +template<typename T> +T neuralNetwork<T>::getOutBase() const { + return outBase; +} + +#ifndef EMSCRIPTEN +template<typename T> +void neuralNetwork<T>::getJSONDescription(Json::Value &jsonModelDescription) { + jsonModelDescription["modelType"] = "Neural Network"; + jsonModelDescription["numInputs"] = numInputs; + jsonModelDescription["whichInputs"] = this->vector2json(whichInputs); + jsonModelDescription["numHiddenLayers"] = numHiddenLayers; + jsonModelDescription["numHiddenNodes"] = numHiddenNodes; + jsonModelDescription["numHiddenOutputs"] = 1; + jsonModelDescription["inRanges"] = this->vector2json(inRanges); + jsonModelDescription["inBases"] = this->vector2json(inBases); + jsonModelDescription["outRange"] = outRange; + jsonModelDescription["outBase"] = outBase; + + //Create Nodes + Json::Value nodes; + + //Output Node + Json::Value outNode; + outNode["name"] = "Linear Node 0"; + for (int i = 0; i < numHiddenNodes; ++i) { + std::string nodeName = "Node " + std::to_string(i + 1); + outNode[nodeName] = wHiddenOutput[i]; + } + outNode["Threshold"] = wHiddenOutput[numHiddenNodes]; + nodes.append(outNode); + + //Input nodes + for (int i = 0; i < weights.size(); ++i) { //layers + for (int j = 0; j < weights[i].size(); ++j) { //hidden nodes + Json::Value tempNode; + tempNode["name"] = "Sigmoid Node " + std::to_string((i * numHiddenNodes) + j + 1); + for (int k = 0; k < weights[i][j].size() - 1; ++ k) { //inputs + threshold aka bias + std::string connectNode = "Attrib inputs-" + std::to_string(k + 1); + tempNode[connectNode] = weights[i][j][k]; + } + tempNode["Threshold"] = weights[i][j][weights[i][j].size() - 1]; + nodes.append(tempNode); + } + } + + jsonModelDescription["nodes"] = nodes; +} +#endif + +template<typename T> +T neuralNetwork<T>::run(const std::vector<T> &inputVector) { + std::vector<T> pattern; + for (int h = 0; h < numInputs; h++) { + pattern.push_back(inputVector[whichInputs[h]]); + } + //set input layer + inputNeurons.clear(); + for (int i = 0; i < numInputs; ++i) { + inputNeurons.push_back((pattern[i] - (inBases[i])) / inRanges[i]); + } + inputNeurons.push_back(1); + + //calculate hidden layers + hiddenNeurons.clear(); + for (int i = 0; i < numHiddenLayers; ++i) { + std::vector<T> layer; + for (int j=0; j < numHiddenNodes; ++j) { + layer.push_back(0); + if (i == 0) { //first hidden layer + for (int k = 0; k <= numInputs; ++k) { + layer[j] += inputNeurons[k] * weights[0][j][k]; + } + } else { + for (int k = 0; k <= numHiddenNodes; ++k) { + layer[j] += hiddenNeurons[i - 1][k] * weights [i][j][k]; + } + } + layer[j] = activationFunction(layer[j]); + } + layer.push_back(1); //for bias weight + hiddenNeurons.push_back(layer); + } + + //calculate output + outputNeuron = 0; + for (int k=0; k <= numHiddenNodes; ++k){ + outputNeuron += hiddenNeurons[numHiddenLayers - 1][k] * wHiddenOutput[k]; + } + //if classifier, outputNeuron = activationFunction(outputNeuron), else... + outputNeuron = (outputNeuron * outRange) + outBase; + return outputNeuron; +} + +template<typename T> +void neuralNetwork<T>::train(const std::vector<trainingExampleTemplate<T > > &trainingSet) { + initTrainer(); + //setup maxes and mins + std::vector<T> inMax = trainingSet[0].input; + std::vector<T> inMin = trainingSet[0].input; + T outMin = trainingSet[0].output[0]; + T outMax = trainingSet[0].output[0]; + for (int ti = 1; ti < (int) trainingSet.size(); ++ti) { + for (int i = 0; i < numInputs; ++i) { + if (trainingSet[ti].input[i] > inMax[i]) { + inMax[i] = trainingSet[ti].input[i]; + } + if (trainingSet[ti].input[i] < inMin[i]) { + inMin[i] = trainingSet[ti].input[i]; + } + if (trainingSet[ti].output[0] > outMax) { + outMax = trainingSet[ti].output[0]; + } + if (trainingSet[ti].output[0] < outMin) { + outMin = trainingSet[ti].output[0]; + } + } + } + inRanges.clear(); + inBases.clear(); + for (int i = 0; i < numInputs; ++i) { + inRanges.push_back((inMax[i] - inMin[i]) * 0.5); + inBases.push_back((inMax[i] + inMin[i]) * 0.5); + } + for (int i = 0; i < inRanges.size(); ++i) { + if (inRanges[i] == 0.) { + inRanges[i] = 1.0; //Prevent divide by zero later. + } + } + outRange = (outMax - outMin) * 0.5; + outBase = (outMax + outMin) * 0.5; + + //train + if (outRange) { //Don't need to do any training if output never changes + for (int epoch = 0; epoch < numEpochs; ++epoch) { + //run through every training instance + for (int ti = 0; ti < (int) trainingSet.size(); ++ti) { + run(trainingSet[ti].input); + backpropagate(trainingSet[ti].output[0]); + } + } + } +} + +template<typename T> +void neuralNetwork<T>::backpropagate(const T &desiredOutput) { + outputErrorGradient = ((desiredOutput - outBase) / outRange) - ((outputNeuron - outBase)/ outRange); //FIXME: could be tighter -MZ + + //correction based on size of last layer. Is this right? -MZ + T length = 0; + for (int i = 0; i < numHiddenNodes; ++i) { + length += hiddenNeurons[numHiddenLayers - 1][i] * hiddenNeurons[numHiddenLayers - 1][i]; + } + length = (length <= 2.0) ? 1.0 : length; + + //deltas between hidden and output + for (int i = 0; i <= numHiddenNodes; ++i) { + deltaHiddenOutput[i] = (learningRate * (hiddenNeurons[numHiddenLayers - 1][i]/length) * outputErrorGradient) + (momentum * deltaHiddenOutput[i]); + } + + //deltas between hidden + for (int i = numHiddenLayers - 1; i >= 0; --i) { + for (int j = 0; j < numHiddenNodes; ++j) { + T hiddenErrorGradient = getHiddenErrorGradient(i, j); + if (i > 0) { + for (int k = 0; k <= numHiddenNodes; ++k) { + deltaWeights[i][j][k] = (learningRate * hiddenNeurons[i][j] * hiddenErrorGradient) + (momentum * deltaWeights[i][j][k]); + } + } else { //hidden to input layer + for (int k = 0; k <= numInputs; ++k) { + deltaWeights[0][j][k] = (learningRate * inputNeurons[k] * hiddenErrorGradient) + (momentum * deltaWeights[0][j][k]); + } + } + } + } + updateWeights(); +} + +template<typename T> +void neuralNetwork<T>::updateWeights() { + //hidden to hidden weights + for (int i = 0; i < numHiddenLayers; ++i) { + int numDeltas = (i == 0) ? numInputs : numHiddenNodes; + for (int j = 0; j < numHiddenNodes; ++j) { + for (int k = 0; k <= numDeltas; ++k) { + weights[i][j][k] += deltaWeights[i][j][k]; + } + } + } + //hidden to output weights + for (int i = 0; i <= numHiddenNodes; ++i) { + wHiddenOutput[i] += deltaHiddenOutput[i]; + } +} + +//explicit instantiation +template class neuralNetwork<double>; +template class neuralNetwork<float>; \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/neuralNetwork.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/neuralNetwork.h new file mode 100644 index 0000000000000000000000000000000000000000..124864df08135e8b61815ee56e782832a2595494 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/neuralNetwork.h @@ -0,0 +1,151 @@ +/** + * @file neuralNetwork.h + * RapidLib + * + * @date 05 Sep 2016 + * @copyright Copyright © 2016 Goldsmiths. All rights reserved. + */ + +#ifndef neuralNetwork_h +#define neuralNetwork_h +#include <vector> +#include "baseModel.h" + +#ifndef EMSCRIPTEN +#include "../dependencies/json/json.h" +#endif + +#define LEARNING_RATE 0.3 +#define MOMENTUM 0.2 +#define NUM_EPOCHS 500 + +/*! Class for implementing a Neural Network. + * + * This class includes both running and training, and constructors for reading trained models from JSON. + */ +template<typename T> +class neuralNetwork : public baseModel<T> { + +public: + /** This is the constructor for building a trained model from JSON. */ + neuralNetwork(const int &num_inputs, + const std::vector<int> &which_inputs, + const int &num_hidden_layers, + const int &num_hidden_nodes, + const std::vector<T> &weights, + const std::vector<T> &wHiddenOutput, + const std::vector<T> &inRanges, + const std::vector<T> &inBases, + const T &outRange, + const T &outBase); + + /** This constructor creates a neural network that needs to be trained. + * + * @param num_inputs is the number of inputs the network will process + * @param which_inputs is an vector of which values in the input vector are being fed to the network. ex: {0,2,4} + * @param num_hidden_layer is the number of hidden layers in the network. Must be at least 1. + * @param num_hidden_nodes is the number of hidden nodes in each hidden layer. Often, this is the same as num_inputs + * + * @return A neuralNetwork instance with randomized weights and no normalization values. These will be set or adjusted during training. + */ + neuralNetwork(const int &num_inputs, + const std::vector<int> &which_inputs, + const int &num_hidden_layer, + const int &num_hidden_nodes); + + /** destructor */ + ~neuralNetwork(); + + /** Generate an output value from a single input vector. + * @param A standard vector of type T that feed-forward regression will run on. + * @return A single value, which is the result of the feed-forward operation + */ + T run(const std::vector<T> &inputVector); + + void reset(); + + int getNumInputs() const; + std::vector<int> getWhichInputs() const; + + int getNumHiddenLayers() const; + void setNumHiddenLayers(int num_hidden_layers); + + int getNumHiddenNodes() const; + + void setEpochs(const int &epochs); + + std::vector<T> getWeights() const; + std::vector<T> getWHiddenOutput() const; + + std::vector<T> getInRanges() const; + std::vector<T> getInBases() const; + T getOutRange() const; + T getOutBase() const; + +#ifndef EMSCRIPTEN + void getJSONDescription(Json::Value ¤tModel); +#endif + + +private: + /** Parameters that describe the topography of the model */ + int numInputs; + std::vector<int> whichInputs; + int numHiddenLayers; + int numHiddenNodes; + + /** Neurons: state is updated on each process(). */ + std::vector<T> inputNeurons; + std::vector<std::vector<T> > hiddenNeurons; + T outputNeuron; + + /** Weights between layers and nodes are kept here. */ + std::vector<std::vector<std::vector<T> > > weights; + std::vector<T> wHiddenOutput; + + /** Normalization parameters */ + std::vector<T> inRanges; + std::vector<T> inBases; + T outRange; + T outBase; + + /** Sigmoid function for activating hidden nodes. */ + inline T activationFunction(T); + + //////////////////////////////////////////////////////////////////////////// + /// These pertain to the training, and aren't need to run a trained model // + +public: + /** Train a model using backpropagation. + * + * @param The training set is a vector of training examples that contain both a vector of input values and a value specifying desired output. + * + */ + void train(const std::vector<trainingExampleTemplate<T> > &trainingSet); + +private: + /** Parameters that influence learning */ + T learningRate; + T momentum; + int numEpochs; + + /** These deltas are applied to the weights in the network */ + std::vector<std::vector< std::vector<T> > > deltaWeights; + std::vector<T> deltaHiddenOutput; + + /** Parameters and functions for calculating amount of change for each weight */ + T outputErrorGradient; + inline T getHiddenErrorGradient(int layer, int neuron); + + void initTrainer(); + + /** Propagate output error back through the network. + * @param The desired output of the network is fed into the function, and compared with the actual output + */ + void backpropagate(const T &desiredOutput); + + /** Apply corrections to network weights, based on output error */ + void updateWeights(); +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/rapidStream.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/rapidStream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f61afe601563437c6c675e780a549809ac8aa3c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/rapidStream.cpp @@ -0,0 +1,186 @@ +/** + * @file rapidStream.cpp + * @author Michael Zbyszynski + * @date 6 Feb 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include "rapidStream.h" +#include <iostream> +#include <cmath> +#include <limits> + +#ifdef EMSCRIPTEN +#include "emscripten/rapidStreamEmbindings.h" +#endif + +template<typename T> +rapidStream<T>::rapidStream(int window_size) { + windowSize = window_size; + windowIndex = 0; + circularWindow = new T[window_size]; + for (int i = 0; i < windowSize; ++i) { + circularWindow[i] = 0; + } +} + +template<typename T> +rapidStream<T>::rapidStream() { + windowSize = 3; + windowIndex = 0; + circularWindow = new T[windowSize]; + for (int i = 0; i < windowSize; ++i) { + circularWindow[i] = 0; + } +} + +template<typename T> +rapidStream<T>::~rapidStream() { + delete []circularWindow; +} + +template<typename T> +void rapidStream<T>::clear() { + windowIndex = 0; + circularWindow = new T[windowSize]; + for (int i = 0; i < windowSize; ++i) { + circularWindow[i] = 0; + } +} + +template<typename T> +void rapidStream<T>::pushToWindow(T input) { + circularWindow[windowIndex] = input; + windowIndex = (windowIndex + 1) % windowSize; +} + +template<typename T> +inline T rapidStream<T>::calcCurrentVel(int i) { + return circularWindow[(i + windowIndex) % windowSize] - circularWindow[(i + windowIndex - 1) % windowSize]; +} + +template<typename T> +T rapidStream<T>::velocity() { + return calcCurrentVel(-1); +}; + +template<typename T> +T rapidStream<T>::acceleration() { + return calcCurrentVel(-2) - calcCurrentVel(-3); +}; + +template<typename T> +T rapidStream<T>::minimum() { + T minimum = std::numeric_limits<T>::infinity(); + for (int i = 0; i < windowSize; ++i) { + if (circularWindow[i] < minimum) { + minimum = circularWindow[i]; + } + } + return minimum; +} + +template<typename T> +T rapidStream<T>::maximum() { + T maximum = std::numeric_limits<T>::min(); + for (int i = 0; i < windowSize; ++i) { + if (circularWindow[i] > maximum) { + maximum = circularWindow[i]; + } + } + return maximum; +} + +template<typename T> +T rapidStream<T>::sum() { + T newSum = 0; + for(int i = 0; i < windowSize; ++i) + { + newSum += circularWindow[i]; + } + return newSum; +} + +template<typename T> +T rapidStream<T>::mean() { + return sum()/windowSize; +} + +template<typename T> +T rapidStream<T>::standardDeviation() { + T newMean = mean(); + T standardDeviation = 0.; + for(int i = 0; i < windowSize; ++i) { + standardDeviation += pow(circularWindow[i] - newMean, 2); + } + return sqrt(standardDeviation / windowSize); +} + +template<typename T> +T rapidStream<T>::rms() { + T rms; + for (int i = 0; i < windowSize; ++i) { + rms += (circularWindow[i] * circularWindow[i]); + } + rms = rms/windowSize; + return sqrt(rms); +} + +template<typename T> +T rapidStream<T>::minVelocity() { + T minVel = std::numeric_limits<T>::infinity(); + for (int i = 0; i < windowSize; ++i) { + T currentVel = calcCurrentVel(i); + if ( currentVel < minVel) { + minVel = currentVel; + } + } + return minVel; +} + +template<typename T> +T rapidStream<T>::maxVelocity() { + T maxVel = std::numeric_limits<T>::lowest(); + for (int i = 0; i < windowSize; ++i) { + T currentVel = calcCurrentVel(i); + if (currentVel > maxVel) { + maxVel = currentVel; + } + } + return maxVel; +} + +template<typename T> +T rapidStream<T>::minAcceleration() { + T minAccel = std::numeric_limits<T>::infinity(); + T lastVel = calcCurrentVel(1); + for (int i = 2; i < windowSize; ++i) { + T currentVel = calcCurrentVel(i); + T currentAccel = currentVel - lastVel; + lastVel = currentVel; + if (currentAccel < minAccel) { + minAccel = currentAccel; + } + } + return minAccel; +} + +template<typename T> +T rapidStream<T>::maxAcceleration() { + T maxAccel = std::numeric_limits<T>::lowest(); + T lastVel = calcCurrentVel(1); + for (int i = 2; i < windowSize; ++i) { + T currentVel = calcCurrentVel(i); + T currentAccel = currentVel - lastVel; + lastVel = currentVel; + if (currentAccel > maxAccel) { + maxAccel = currentAccel; + } + } + return maxAccel; +} + +//explicit instantiation +template class rapidStream<double>; +template class rapidStream<float>; + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/rapidStream.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/rapidStream.h new file mode 100644 index 0000000000000000000000000000000000000000..7e4357eab396da3ab2394acec0aadb733a07b4b3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/rapidStream.h @@ -0,0 +1,108 @@ +/** + * @file rapidStream.h + * @author Michael Zbyszynski + * @date 6 Feb 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef rapidStream_h +#define rapidStream_h + +#include <stdint.h> + +template<typename T> +class rapidStream { +public: + + /** + * Create a circular buffer with 3 elements. + */ + rapidStream(); + /** + * Create a circular buffer with an arbitrary number of elements. + * @param int: number of elements to hold in the buffer + */ + rapidStream(int windowSize); + + ~rapidStream(); + + /** + * Resets all the values in the buffer to zero. + */ + void clear(); + + /** Add a value to a circular buffer whose size is defined at creation. + * @param double: value to be pushed into circular buffer. + */ + void pushToWindow(T input); + + /** Calculate the first-order difference (aka velocity) between the last two inputs. + * @return double: difference between last two inputs. + */ + T velocity(); + + /** Calculate the second-order difference (aka acceleration) over the last three inputs. + * @return double: acceleration over the last three inputs. + */ + T acceleration(); + + /** Find the minimum value in the buffer. + * @return double: minimum. + */ + T minimum(); + + /** Find the maximum value in the buffer. + * @return double: maximum. + */ + T maximum(); + + /** Calculate the sum of all values in the buffer. + * @return double: sum. + */ + T sum(); + + /** Calculate the mean of all values in the buffer. + * @return double: mean. + */ + T mean(); + + /** Calculate the standard deviation of all values in the buffer. + * @return double: standard deviation. + */ + T standardDeviation(); + + /** Calculate the root mean square of the values in the buffer + * @return double: rms + */ + T rms(); + + /** Calculate the minimum first-order difference over consecutive inputs in the buffer. + * @return double: minimum velocity. + */ + T minVelocity(); + + /** Calculate the maximum first-order difference over consecutive inputs in the buffer. + * @return double: maximum velocity. + */ + T maxVelocity(); + + /** Calculate the minimum second-order difference over consecutive inputs in the buffer. + * @return double: minimum acceleration. + */ + T minAcceleration(); + + /** Calculate the maximum second-order difference over consecutive inputs in the buffer. + * @return double: maximum acceleration. + */ + T maxAcceleration(); + +private: + uint32_t windowSize; + uint32_t windowIndex; + T *circularWindow; + + T calcCurrentVel(int i); +}; + + +#endif \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/regression.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/regression.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45be22eaa9438b036963313418270f4198f6c5eb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/regression.cpp @@ -0,0 +1,133 @@ +/** + * @file regression.cpp + * RapidLib + * + * @author Michael Zbsyzynski + * @date 26 Sep 2016 + * @copyright Copyright © 2016 Goldsmiths. All rights reserved. + */ + +#include <vector> +#include "regression.h" + + +#ifdef EMSCRIPTEN +#include "emscripten/regressionEmbindings.h" +#endif + +template<typename T> +regressionTemplate<T>::regressionTemplate() { + modelSet<T>::numInputs = 0; + modelSet<T>::numOutputs = 0; + numHiddenLayers = 1; + numEpochs = 500; + modelSet<T>::created = false; +}; + +template<typename T> +regressionTemplate<T>::regressionTemplate(const int &num_inputs, const int &num_outputs) { + modelSet<T>::numInputs = num_inputs; + modelSet<T>::numOutputs = num_outputs; + numHiddenLayers = 1; + numEpochs = 500; + modelSet<T>::created = false; + std::vector<int> whichInputs; + for (int i = 0; i < modelSet<T>::numInputs; ++i) { + whichInputs.push_back(i); + } + for (int i = 0; i < modelSet<T>::numOutputs; ++i) { + modelSet<T>::myModelSet.push_back(new neuralNetwork<T>(modelSet<T>::numInputs, whichInputs, numHiddenLayers, modelSet<T>::numInputs)); + } + modelSet<T>::created = true; +}; + +template<typename T> +regressionTemplate<T>::regressionTemplate(const std::vector<trainingExampleTemplate<T> > &training_set) { + modelSet<T>::numInputs = 0; + modelSet<T>::numOutputs = 0; + modelSet<T>::created = false; + train(training_set); +}; + +template<typename T> +std::vector<int> regressionTemplate<T>::getNumHiddenLayers() { + std::vector<int> vecNumHiddenLayers; + if (std::begin(modelSet<T>::myModelSet) != std::end(modelSet<T>::myModelSet)) { + for (baseModel<T>* model : modelSet<T>::myModelSet) { + neuralNetwork<T>* nnModel = dynamic_cast<neuralNetwork<T>*>(model); //FIXME: I really dislike this design + vecNumHiddenLayers.push_back(nnModel->getNumHiddenLayers()); + } + } else { + vecNumHiddenLayers = { numHiddenLayers }; + } + return vecNumHiddenLayers; +} + +template<typename T> +void regressionTemplate<T>::setNumHiddenLayers(const int &num_hidden_layers){ + numHiddenLayers = num_hidden_layers; + //Set any existing models + if (std::begin(modelSet<T>::myModelSet) != std::end(modelSet<T>::myModelSet)) { + for (baseModel<T>* model : modelSet<T>::myModelSet) { + neuralNetwork<T>* nnModel = dynamic_cast<neuralNetwork<T>*>(model); //FIXME: I really dislike this design + nnModel->setNumHiddenLayers(num_hidden_layers); + } + } +} + +template<typename T> +void regressionTemplate<T>::setNumEpochs(const int &epochs) { + numEpochs = epochs; + //set any existing models + if (std::begin(modelSet<T>::myModelSet) != std::end(modelSet<T>::myModelSet)) { + for (baseModel<T>* model : modelSet<T>::myModelSet) { + neuralNetwork<T>* nnModel = dynamic_cast<neuralNetwork<T>*>(model); //FIXME: I really dislike this design + nnModel->setEpochs(epochs); + } + } +} + +template<typename T> +bool regressionTemplate<T>::train(const std::vector<trainingExampleTemplate<T> > &training_set) { + //TODO: time this process? + if (training_set.size() > 0) { + if (modelSet<T>::created) { + return modelSet<T>::train(training_set); + } else { + //create model(s) here + modelSet<T>::numInputs = int(training_set[0].input.size()); + for (int i = 0; i < modelSet<T>::numInputs; ++i) { + modelSet<T>::inputNames.push_back("inputs-" + std::to_string(i + 1)); + } + modelSet<T>::numOutputs = int(training_set[0].output.size()); + for ( auto example : training_set) { + if (example.input.size() != modelSet<T>::numInputs) { + return false; + } + if (example.output.size() != modelSet<T>::numOutputs) { + return false; + } + } + std::vector<int> whichInputs; + for (int j = 0; j < modelSet<T>::numInputs; ++j) { + whichInputs.push_back(j); + } + for (int i = 0; i < modelSet<T>::numOutputs; ++i) { + modelSet<T>::myModelSet.push_back(new neuralNetwork<T>(modelSet<T>::numInputs, whichInputs, numHiddenLayers, modelSet<T>::numInputs)); + } + if (numEpochs != 500) { + for (baseModel<T>* model : modelSet<T>::myModelSet) { + neuralNetwork<T>* nnModel = dynamic_cast<neuralNetwork<T>*>(model); //FIXME: I really dislike this design + nnModel->setEpochs(numEpochs); + } + } + modelSet<T>::created = true; + return modelSet<T>::train(training_set); + } + } + return false; +} + +//explicit instantiation +template class regressionTemplate<double>; +template class regressionTemplate<float>; diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/regression.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/regression.h new file mode 100644 index 0000000000000000000000000000000000000000..194e1e9f692ae880cd404ddd9a00832ef9b51279 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/regression.h @@ -0,0 +1,55 @@ +/** + * @file regression.h + * RapidLib + * + * @author Michael Zbsyzynski + * @date 26 Sep 2016 + * @copyright Copyright © 2016 Goldsmiths. All rights reserved. + */ + +#ifndef regression_h +#define regression_h + +#include <vector> +#include "modelSet.h" + +/*! Class for implementing a set of regression models. + * + * This doesn't do anything modelSet can't do. But, it's simpler and more like wekinator. + */ + +template<typename T> +class regressionTemplate : public modelSet<T> { +public: + /** with no arguments, just make an empty vector */ + regressionTemplate(); + /** create based on training set inputs and outputs */ + regressionTemplate(const std::vector<trainingExampleTemplate<T> > &trainingSet); + /** create with proper models, but not trained */ + regressionTemplate(const int &numInputs, const int &numOutputs); + + /** destructor */ + ~regressionTemplate() {}; + + /** Train on a specified set, causes creation if not created */ + bool train(const std::vector<trainingExampleTemplate<T> > &trainingSet); + + /** Call before train, to set the number of training epochs */ + void setNumEpochs(const int &epochs); + + /** Check how many hidden layers are in each model. This feature is temporary, and will be replaced by a different design. */ + std::vector<int> getNumHiddenLayers(); + + /** Set how many hidden layers are in all models. This feature is temporary, and will be replaced by a different design. */ + void setNumHiddenLayers(const int &num_hidden_layers); + +private: + int numHiddenLayers; //Temporary -- this should be part of the nn class. -mz + int numEpochs; //Temporary -- also should be part of nn only. -mz +}; + +//This is here so the old API still works +using regression = regressionTemplate<double>; +using regressionFloat = regressionTemplate<float>; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/searchWindow.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/searchWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a08a5f8c84feb60a1aa88b0f75cc59ab4075a46 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/searchWindow.cpp @@ -0,0 +1,190 @@ +/** + * @file searchWindow.cpp + * RapidLib + * @author Michael Zbyszynski + * @date 14 Sep 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include "searchWindow.h" + +template<typename T> +searchWindow<T>::searchWindow(const int seriesXSize, const int seriesYSize, const warpPath &shrunkenWarpPath, const int searchRadius) : +minValues(seriesXSize, -1), maxValues(seriesXSize, 0), maxY(seriesYSize - 1) { + + //Current location of higher resolution path + int currentX = shrunkenWarpPath.xIndices[0]; + int currentY = shrunkenWarpPath.yIndices[0]; + + //Last evaluated part of low resolution path + int lastWarpedX = std::numeric_limits<int>::max(); + int lastWarpedY = std::numeric_limits<int>::max(); + + int blockSize = 2; //TODO: something other than 2? Different for x and y? + + //project each part of the low-res path to high res cells + for (int i = 0; i < shrunkenWarpPath.xIndices.size(); ++i) { + + int warpedX = shrunkenWarpPath.xIndices[i]; + int warpedY = shrunkenWarpPath.yIndices[i]; + + if (warpedX > lastWarpedX) { + currentX += blockSize; + } + if (warpedY > lastWarpedY) { + currentY += blockSize; + } + + if ((warpedX > lastWarpedX) && (warpedY > lastWarpedY)) + { + markVisited(currentX-1, currentY); + markVisited(currentX, currentY-1); + } + + for (int j = 0; j < blockSize; ++j) { + markVisited(currentX + j, currentY); + markVisited(currentX + j, currentY + blockSize - 1); //TODO: These are redundant? + } + + lastWarpedX = warpedX; + lastWarpedY = warpedY; + } + + if (searchRadius > 0) { + expandWindow(1); + expandWindow(searchRadius-1); + } +} + +template<typename T> +void searchWindow<T>::markVisited(int col, int row) { + if (row <= maxY && col < minValues.size()) { //Don't mark beyond the edge of the window + if (minValues[col] == -1) { + minValues[col] = row; + maxValues[col] = row; + //size++; + } else if (minValues[col] > row) { + //size += minValues[col] - row; + minValues[col] = row; + } else if (maxValues[col] < row) { + //size += row - maxValues[col]; + maxValues[col] = row; + } + } +} + +template<typename T> +void searchWindow<T>::expandWindow(int radius) { + if (radius > 0) { + + //Add all cells in the current window to a vector. + std::vector<std::pair<int, int>> windowCells; + for (int currentX = 0; currentX < minValues.size(); ++currentX) { + for (int currentY = minValues[currentX]; currentY <= maxValues[currentX]; ++currentY) { + std::pair<int, int> currentCell = std::make_pair(currentX, currentY); + windowCells.push_back(currentCell); + } + } + + int maxX = int(minValues.size() - 1); + + for (int cell = 0; cell < windowCells.size(); ++cell) { + std::pair<int, int> currentCell = windowCells[cell]; //TODO: is pair necessary? easier to make currentX and currentY? + + if (currentCell.first != 0 && currentCell.second != maxY) { //move to upper left if possible + //expand until edges are met + int targetX = currentCell.first - radius; + int targetY = currentCell.second + radius; + + if (targetX >= 0 && targetY <= maxY) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = std::max(0 - targetX, targetY - maxY); + markVisited(targetX + cellsPastEdge, targetY + cellsPastEdge); + } + } + + if (currentCell.second != maxY) { //move up if possible + int targetX = currentCell.first; + int targetY = currentCell.second + radius; + if (targetY <= maxY) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = targetY - maxY; + markVisited(targetX, targetY - cellsPastEdge); + } + } + + if (currentCell.first != maxX && currentCell.second != maxY) { //move upper right if possible + int targetX = currentCell.first + radius; + int targetY = currentCell.second + radius; + if (targetX <= maxX && targetY <= maxY) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = std::max(targetX - maxX, targetY - maxY); + markVisited(targetX - cellsPastEdge, targetY - cellsPastEdge); + } + } + + if (currentCell.first != 0) { //move left if possible + int targetX = currentCell.first - radius; + int targetY = currentCell.second; + if (targetX != 0) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = (0 - targetX); + markVisited(targetX + cellsPastEdge, targetY); + } + } + + if (currentCell.first != maxX) { //move right if possible + int targetX = currentCell.first + radius; + int targetY = currentCell.second; + if (targetX <= maxX) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = (targetX - maxX); + markVisited(targetX - cellsPastEdge, targetY); + } + } + + if (currentCell.first != 0 && currentCell.second != 0) { //move to lower left if possible + int targetX = currentCell.first - radius; + int targetY = currentCell.second - radius; + + if (targetX >= 0 && targetY >= 0) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = std::max(0 - targetX, 0 - targetY); + markVisited(targetX + cellsPastEdge, targetY + cellsPastEdge); + } + } + + if (currentCell.second != 0) { //move down if possible + int targetX = currentCell.first; + int targetY = currentCell.second - radius; + if (targetY >= 0) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = 0 - targetY; + markVisited(targetX, targetY + cellsPastEdge); + } + } + + if (currentCell.first != maxX && currentCell.second != 0) { //move lower right if possible + int targetX = currentCell.first + radius; + int targetY = currentCell.second - radius; + if (targetX <= maxX && targetY >= 0) { + markVisited(targetX, targetY); + } else { + int cellsPastEdge = std::max(targetX - maxX, 0 - targetY); + markVisited(targetX - cellsPastEdge, targetY + cellsPastEdge); + } + } + } + } +} + +//explicit instantiation +template class searchWindow<double>; +template class searchWindow<float>; \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/searchWindow.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/searchWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..b3684eb1afd4bf35cb42424dc7d75e256406c540 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/searchWindow.h @@ -0,0 +1,36 @@ +/** + * @file searchWindow.h + * RapidLib + * @author Michael Zbyszynski + * @date 14 Sep 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef searchWindow_h +#define searchWindow_h + +#include <vector> +#include "warpPath.h" + +/** For fastDTW, a window of cells to calculate costs for. + * These are cells within a specified search radius of a lower resolution path. + */ +template<typename T> +class searchWindow { +public: + searchWindow(const int seriesXSize, + const int seriesYSize, + const warpPath &shrunkenWarpPath, + const int searchRadius); + + std::vector<int> minValues; + std::vector<int> maxValues; + +private: + int maxY; + //int size; + void markVisited(int col, int row); + void expandWindow(int searchRadius); +}; + +#endif /* searchWindow_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/seriesClassification.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/seriesClassification.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf8728c1cf16453f800df15aa8a6e1bf21aa916c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/seriesClassification.cpp @@ -0,0 +1,201 @@ +/** + * @file seriesClassification.cpp + * RapidLib + * + * @author Michael Zbyszynski + * @date 08 Jun 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include <vector> +#include <cassert> +#include "seriesClassification.h" +#ifdef EMSCRIPTEN +#include "emscripten/seriesClassificationEmbindings.h" +#endif + +#define SEARCH_RADIUS 1 + +template<typename T> +seriesClassificationTemplate<T>::seriesClassificationTemplate() {}; + +template<typename T> +seriesClassificationTemplate<T>::~seriesClassificationTemplate() {}; + +template<typename T> +bool seriesClassificationTemplate<T>::train(const std::vector<trainingSeriesTemplate<T> > &seriesSet) { + assert(seriesSet.size() > 0); + reset(); + bool trained = true; + allTrainingSeries = seriesSet; + minLength = maxLength = int(allTrainingSeries[0].input.size()); + for (int i = 0; i < allTrainingSeries.size(); ++i) { + //Global + int newLength = int(allTrainingSeries[i].input.size()); + if (newLength < minLength) { + minLength = newLength; + } + if (newLength > maxLength) { + maxLength = newLength; + } + //Per Label + typename std::map<std::string, minMax<int> >::iterator it = lengthsPerLabel.find(allTrainingSeries[i].label); + if (it != lengthsPerLabel.end()) { + int newLength = int(allTrainingSeries[i].input.size()); + if (newLength < it->second.min) { + it->second.min = newLength; + } + if (newLength > it->second.max) { + it->second.max = newLength; + } + } else { + minMax<int> tempLengths; + tempLengths.min = tempLengths.max = int(allTrainingSeries[i].input.size()); + lengthsPerLabel[allTrainingSeries[i].label] = tempLengths; + } + } + return trained; +}; + +template<typename T> +void seriesClassificationTemplate<T>::reset() { + allCosts.clear(); + allTrainingSeries.clear(); + lengthsPerLabel.clear(); + minLength = -1; + maxLength = -1; +} + +template<typename T> +std::string seriesClassificationTemplate<T>::run(const std::vector<std::vector<T>> &inputSeries) { + //TODO: Check to see if trained + int closestSeries = 0; + allCosts.clear(); + T lowestCost = fastDTW<T>::getCost(inputSeries, allTrainingSeries[0].input, SEARCH_RADIUS); + allCosts.push_back(lowestCost); + + for (int i = 1; i < allTrainingSeries.size(); ++i) { + T currentCost = fastDTW<T>::getCost(inputSeries, allTrainingSeries[i].input, SEARCH_RADIUS); + allCosts.push_back(currentCost); + if (currentCost < lowestCost) { + lowestCost = currentCost; + closestSeries = i; + } + } + return allTrainingSeries[closestSeries].label; +}; + +template<typename T> +T seriesClassificationTemplate<T>::run(const std::vector<std::vector<T>> &inputSeries, std::string label) { + //TODO: Check to see if trained + int closestSeries = 0; + allCosts.clear(); + T lowestCost = std::numeric_limits<T>::max(); + for (int i = 0; i < allTrainingSeries.size(); ++i) { + if (allTrainingSeries[i].label == label) { + T currentCost = fastDTW<T>::getCost(inputSeries, allTrainingSeries[i].input, SEARCH_RADIUS); + allCosts.push_back(currentCost); + if (currentCost < lowestCost) { + lowestCost = currentCost; + closestSeries = i; + } + } + } + return lowestCost; +}; + +template<typename T> +std::vector<T> seriesClassificationTemplate<T>::getCosts() const{ + return allCosts; +} + +template<typename T> +int seriesClassificationTemplate<T>::getMinLength() const{ + return minLength; +} + +template<typename T> +int seriesClassificationTemplate<T>::getMinLength(std::string label) const { + int labelMinLength = -1; + typename std::map<std::string, minMax<int> >::const_iterator it = lengthsPerLabel.find(label); + if (it != lengthsPerLabel.end()) { + labelMinLength = it->second.min; + } + return labelMinLength; +} + +template<typename T> +int seriesClassificationTemplate<T>::getMaxLength() const { + return maxLength; +} + +template<typename T> +int seriesClassificationTemplate<T>::getMaxLength(std::string label) const { + int labelMaxLength = -1; + typename std::map<std::string, minMax<int> >::const_iterator it = lengthsPerLabel.find(label); + if (it != lengthsPerLabel.end()) { + labelMaxLength = it->second.max; + } + return labelMaxLength; +} + +template<typename T> +seriesClassificationTemplate<T>::minMax<T> seriesClassificationTemplate<T>::calculateCosts(std::string label) const { + minMax<T> calculatedMinMax; + bool foundSeries = false; + std::vector<T> labelCosts; + for (int i = 0; i < (allTrainingSeries.size() - 1); ++i) { //these loops are a little different than the two-label case + if (allTrainingSeries[i].label == label) { + foundSeries = true; + for (int j = (i + 1); j < allTrainingSeries.size(); ++j) { + if (allTrainingSeries[j].label == label) { + labelCosts.push_back(fastDTW<T>::getCost(allTrainingSeries[i].input, allTrainingSeries[j].input, SEARCH_RADIUS)); + } + } + } + } + if (foundSeries) { + auto minmax_result = std::minmax_element(std::begin(labelCosts), std::end(labelCosts)); + calculatedMinMax.min = *minmax_result.first; + calculatedMinMax.max = *minmax_result.second; + } else { + calculatedMinMax.min = calculatedMinMax.max = 0; + } + return calculatedMinMax; +} + +template<typename T> +seriesClassificationTemplate<T>::minMax<T> seriesClassificationTemplate<T>::calculateCosts(std::string label1, std::string label2) const { + minMax<T> calculatedMinMax; + bool foundSeries = false; + std::vector<T> labelCosts; + for (int i = 0; i < (allTrainingSeries.size()); ++i) { + if (allTrainingSeries[i].label == label1) { + for (int j = 0; j < allTrainingSeries.size(); ++j) { + if (allTrainingSeries[j].label == label2) { + foundSeries = true; + labelCosts.push_back(fastDTW<T>::getCost(allTrainingSeries[i].input, allTrainingSeries[j].input, SEARCH_RADIUS)); + } + } + } + } + if (foundSeries) { + auto minmax_result = std::minmax_element(std::begin(labelCosts), std::end(labelCosts)); + calculatedMinMax.min = *minmax_result.first; + calculatedMinMax.max = *minmax_result.second; + } else { + calculatedMinMax.min = calculatedMinMax.max = 0; + } + return calculatedMinMax; +} + +//explicit instantiation +template class seriesClassificationTemplate<double>; +template class seriesClassificationTemplate<float>; + + +// +//std::vector<T> seriesClassification::getCosts(const std::vector<trainingExample> &trainingSet) { +// run(trainingSet); +// return allCosts; +//} \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/seriesClassification.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/seriesClassification.h new file mode 100644 index 0000000000000000000000000000000000000000..d76a20adeefc5e00e9433a1935ecd2bef14bbd31 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/seriesClassification.h @@ -0,0 +1,112 @@ +/** + * @file seriesClassification.h + * RapidLib + * + * @author Michael Zbyszynski + * @date 08 Jun 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef seriesClassification_hpp +#define seriesClassification_hpp + +#include <vector> +#include <string> +#include <map> +#include "fastDTW.h" +#include "trainingExample.h" + +/** Class for containing time series classifiers. + * + * Currently only (fast)DTW. + */ + +template<typename T> +class seriesClassificationTemplate { +public: + + /** Constructor, no params */ + seriesClassificationTemplate(); + ~seriesClassificationTemplate(); + + /** Train on a specified set of trainingSeries + * @param std::vector<trainingSeries> A vector of training series + */ + bool train(const std::vector<trainingSeriesTemplate<T> > &seriesSet); + + /** Reset model to its initial state, forget all costs and training data*/ + void reset(); + + /** Compare an input series to the stored training series + * @param std::vector<std::vector> vector of vectors, either float or double input data + * @return The label of the closest training series. + */ + std::string run(const std::vector<std::vector<T> > &inputSeries); + + /** Compare an input series to all of the stored series with a specified label + * @param std::vector<std::vector> either float or double input data + * @param String label to compare with + * @return The lowest cost match, float or double + */ + T run(const std::vector<std::vector<T> > &inputSeries, std::string label); + + /** Get the costs that were calculated by the run method + * @return A vector of floats or doubles, the cost of matching to each training series + */ + std::vector<T> getCosts() const; + + /** Get minimum training series length + * @return The minimum length training series + */ + int getMinLength() const; + + /** Get minimum training series length from a specified label + * @param string The label to check + * @return The minimum length training series of that label + */ + int getMinLength(std::string label) const; + + /** Get maximum training series length + * @return The maximum length training series + */ + int getMaxLength() const; + + /** Get maximum training series length from a specified label + * @param string The label to check + * @return The maximum length training series of that label + */ + int getMaxLength(std::string label) const; + + /** Return struct for calculate costs */ + template<typename TT> + struct minMax { + TT min; + TT max; + }; + + /** Calculate minimum and maximum cost between examples in a label. + * @param string Label to calculate + * @return minMax struct containing min and max + */ + minMax<T> calculateCosts(std::string label) const; + + /** Calculate minimum and maximum cost between examples in one label and examples in a second. + * @param string first label to compare + * @param string second label to compare + * @return minMax struct containing min and max + */ + minMax<T> calculateCosts(std::string label1, std::string label2) const; + +private: + std::vector<trainingSeriesTemplate<T> > allTrainingSeries; + std::vector<T> allCosts; + int maxLength; + int minLength; + std::map<std::string, minMax<int> > lengthsPerLabel; +}; + +//This is here to keep the old API working +using seriesClassification = seriesClassificationTemplate<double>; +using seriesClassificationFloat = seriesClassificationTemplate<float>; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/svmClassification.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/svmClassification.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51953161f1ddcf483ddc7924e7eb6f2accdf451e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/svmClassification.cpp @@ -0,0 +1,269 @@ +/** + * @file svmClassification.cpp + * RapidLib + * + * @author Michael Zbyszynski + * @date 23 Feb 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include <iostream> +#include "svmClassification.h" +#ifdef EMSCRIPTEN +#include "emscripten/svmEmbindings.h" +#endif + +template<typename T> +svmClassification<T>::svmClassification( + KernelType kernelType, + SVMType svmType, + bool useScaling, + bool useNullRejection, + bool useAutoGamma, + float gamma, + unsigned int degree, + float coef0, + float nu, + float C, + bool useCrossValidation, + unsigned int kFoldValue + ) +{ + + //Setup the default SVM parameters + model = NULL; + problem.l = 0; + problem.x = NULL; + problem.y = NULL; + trained = false; + problemSet = false; + param.svm_type = C_SVC; + param.kernel_type = POLY_KERNEL; //LINEAR_KERNEL; + param.degree = 3; + param.gamma = 0; + param.coef0 = 0; + param.nu = 0.5; + param.cache_size = 100; + param.C = 1; + param.eps = 1e-3; + param.p = 0.1; + param.shrinking = 1; + param.probability = 1; + param.nr_weight = 0; + param.weight_label = NULL; + param.weight = NULL; + + //These are from GTK? + /* + this->useScaling = false; + this->useCrossValidation = false; + this->useNullRejection = false; + this->useAutoGamma = true; + classificationThreshold = 0.5; + crossValidationResult = 0; + + classifierMode = STANDARD_CLASSIFIER_MODE; + */ + init(kernelType,svmType,useScaling,useNullRejection,useAutoGamma,gamma,degree,coef0,nu,C,useCrossValidation,kFoldValue); +} + +template<typename T> +svmClassification<T>::svmClassification(int num_inputs) { + + numInputs = num_inputs; + + //Setup the default SVM parameters + model = NULL; + param.weight_label = NULL; + param.weight = NULL; + problem.l = 0; + problem.x = NULL; + problem.y = NULL; + trained = false; + problemSet = false; + param.svm_type = C_SVC; + param.kernel_type = POLY_KERNEL; //LINEAR_KERNEL; + param.degree = 3; + param.gamma = 0; + param.coef0 = 0; + param.nu = 0.5; + param.cache_size = 100; + param.C = 1; + param.eps = 1e-3; + param.p = 0.1; + param.shrinking = 1; + param.probability = 1; + param.nr_weight = 0; + param.weight_label = NULL; + param.weight = NULL; + +} + +template<typename T> +svmClassification<T>::~svmClassification() { + +} + +template<typename T> +void svmClassification<T>::reset() { + //TODO: implement me +} + +template<typename T> +bool svmClassification<T>::init( + KernelType kernelType, + SVMType svmType, + bool useScaling, + bool useNullRejection, + bool useAutoGamma, + float gamma, + unsigned int degree, + float coef0, + float nu, + float C, + bool useCrossValidation, + unsigned int kFoldValue + ){ + + /* + //Clear any previous models or problems + clear(); + + //Validate the kernerlType + if( !validateKernelType(kernelType) ){ + errorLog << __GRT_LOG__ << " Unknown kernelType!\n"; + return false; + } + + if( !validateSVMType(svmType) ){ + errorLog << __GRT_LOG__ << " Unknown kernelType!\n"; + return false; + } + */ + + param.svm_type = (int)svmType; + param.kernel_type = (int)kernelType; + param.degree = (int)degree; + param.gamma = gamma; + param.coef0 = coef0; + param.nu = nu; + param.cache_size = 100; + param.C = C; + param.eps = 1e-3; + param.p = 0.1; + param.shrinking = 1; + param.probability = 1; + param.nr_weight = 0; + param.weight_label = NULL; + param.weight = NULL; + /* + this->useScaling = useScaling; + this->useCrossValidation = useCrossValidation; + this->useNullRejection = useNullRejection; + this->useAutoGamma = useAutoGamma; + classificationThreshold = 0.5; + crossValidationResult = 0; + */ + + return true; +} + +template<typename T> +void svmClassification<T>::train(const std::vector<trainingExampleTemplate<T> > &trainingSet) { + //TODO: should be scaling data -1 to 1 + //Get normalization parameters + std::vector<T> inMax = trainingSet[0].input; + std::vector<T> inMin = trainingSet[0].input; + for (int ti = 1; ti < (int) trainingSet.size(); ++ti) { + for (int i = 0; i < numInputs; ++i) { + if (trainingSet[ti].input[i] > inMax[i]) { + inMax[i] = trainingSet[ti].input[i]; + } + if (trainingSet[ti].input[i] < inMin[i]) { + inMin[i] = trainingSet[ti].input[i]; + } + } + } + inRanges.clear(); + inBases.clear(); + for (int i = 0; i < numInputs; ++i) { + inRanges.push_back((inMax[i] - inMin[i]) * 0.5); + inBases.push_back((inMax[i] + inMin[i]) * 0.5); + } + for (int i = 0; i < inRanges.size(); ++i) { + if (inRanges[i] == 0.) { + inRanges[i] = 1.0; //Prevent divide by zero later. + } + } + + //initialize problem + problem.l = 0; + problem.x = NULL; + problem.y = NULL; + + //SVM problem has: + int numberOfExamples = int(trainingSet.size()); + int numberOfFeatures = int(trainingSet[0].input.size()); + problem.l = numberOfExamples; + problem.x = new LIBSVM::svm_node*[numberOfExamples]; + problem.y = new double[numberOfExamples]; + for (int i = 0; i < numberOfExamples; i++) { + problem.y[i] = trainingSet[i].output[0]; //model set makes this a one item list + problem.x[i] = new LIBSVM::svm_node[numberOfFeatures + 1]; //dummy node at the end of array + for (int j = 0; j < numberOfFeatures; j++) { + // x = svn_nodes[] == index and value pairs + problem.x[i][j].index = j + 1; + problem.x[i][j].value = ((trainingSet[i].input[j] - inBases[j]) / inRanges[j]); //TODO: make normalization optional + } + problem.x[i][numberOfFeatures].index = -1; //Assign the final node value + problem.x[i][numberOfFeatures].value = 0; + } + + model = LIBSVM::svm_train(&problem, ¶m); + trained = true; +}; + +template<typename T> +T svmClassification<T>::run(const std::vector<T> &inputVector) { + if (trained) { + double predictedClass = 0.; + + //Change to LIBSVM format + LIBSVM::svm_node *inputNodes = NULL; + inputNodes = new LIBSVM::svm_node[numInputs + 1]; + for (int i = 0; i < numInputs; i++) { + inputNodes[i].index = i + 1; + inputNodes[i].value = ((inputVector[i] - inBases[i]) / inRanges[i]); //TODO: make normalization optional + } + inputNodes[numInputs].index = -1; + inputNodes[numInputs].value = 0; + + predictedClass = LIBSVM::svm_predict(model, inputNodes); + delete[] inputNodes; + return predictedClass; + } else { + return 0; + } +} + +template<typename T> +int svmClassification<T>::getNumInputs() const { + return 0; +}; + +template<typename T> +std::vector<int> svmClassification<T>::getWhichInputs() const { + std::vector<int> returnVec; + return returnVec; +}; + +#ifndef EMSCRIPTEN +template<typename T> +void svmClassification<T>::getJSONDescription(Json::Value ¤tModel){ + +}; +#endif + +//explicit instantiation +template class svmClassification<double>; +template class svmClassification<float>; diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/svmClassification.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/svmClassification.h new file mode 100644 index 0000000000000000000000000000000000000000..a1885ed90876067a1422d31f7ee51ed214004f2b --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/svmClassification.h @@ -0,0 +1,133 @@ +/** + * @file svmClassification.h + * RapidLib + * + * @author Michael Zbyszynski + * @date 23 Feb 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef svm_h +#define svm_h + +#include <vector> +#include "baseModel.h" +#include "../dependencies/libsvm/libsvm.h" + +template<typename T> +class svmClassification : public baseModel<T> { + +public: + enum SVMType{ C_SVC = 0, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR }; + enum KernelType{ LINEAR_KERNEL = 0, POLY_KERNEL, RBF_KERNEL, SIGMOID_KERNEL, PRECOMPUTED_KERNEL }; + + /** + Default constructor. + + Set the initial SVM settings, although these can be changed at any time using either init(...) function of the set... functions. + + @param kernelType: this sets the SVM kernelType. Options are LINEAR_KERNEL, POLY_KERNEL, RBF_KERNEL, SIGMOID_KERNEL, PRECOMPUTED_KERNEL. The default kernelType is kernelType=LINEAR_KERNEL + @param svmType: this sets the SVM type. Options are C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR. The default svmType is svmType=C_SVC + @param useScaling: sets if the training/prediction data will be scaled to the default range of [-1. 1.]. The SVM algorithm commonly achieves a better classification result if scaling is turned on. The default useScaling value is useScaling=true + @param useNullRejection: sets if a predicted class will be rejected if the classes' probability is below the classificationThreshold. The default value is useNullRejection=false + @param useAutoGamma: sets if the SVM gamma parameter will automatically be computed, if set to true then gamma will be set to (1.0/numFeatures), where numFeatures is the number of features in the training data. The default value is useAutoGamma=true + @param gamma: sets the SVM gamma parameter. The default value is gamma=0.1 + @param degree: sets the SVM degree parameter. The default value is degree=3 + @param coef0: sets the SVM coef0 parameter. The default value is coef0=0 + @param nu: sets the SVM nu parameter. The default value is nu=0.5 + @param C: sets the SVM C parameter. The default value is C=1 + @param useCrossValidation: sets if the SVM model will be trained using cross validation. The default value is useCrossValidation=false + @param kFoldValue: sets the number of folds that will be used for cross validation. The default value is kFoldValue=10 + */ + + svmClassification( + KernelType kernelType = LINEAR_KERNEL, + SVMType svmType = C_SVC, + bool useScaling = true, + bool useNullRejection = false, + bool useAutoGamma = true, + float gamma = 0.1, + unsigned int degree = 3, + float coef0 = 0, + float nu = 0.5, + float C = 1, + bool useCrossValidation = false, + unsigned int kFoldValue = 10 + ); + + svmClassification(int numInputs); + + /** Destructor */ + ~svmClassification(); + + /** Fill the model with a vector of examples. + * + * @param The training set is a vector of training examples that contain both a vector of input values and a double specifying desired output class. + * + */ + void train(const std::vector<trainingExampleTemplate<T> > &trainingSet); + + /** Generate an output value from a single input vector. + * @param A standard vector of doubles to be evaluated. + * @return A single double: the nearest class as determined by k-nearest neighbor. + */ + T run(const std::vector<T> &inputVector); + + void reset(); + + /** + This initializes the SVM settings and parameters. Any previous model, settings, or problems will be cleared. + + @param kernelType: this sets the SVM kernelType. Options are LINEAR_KERNEL, POLY_KERNEL, RBF_KERNEL, SIGMOID_KERNEL, PRECOMPUTED_KERNEL + @param UINT svmType: this sets the SVM type. Options are C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR + @param useScaling: sets if the training/prediction data will be scaled to the default range of [-1. 1.]. The SVM algorithm commonly achieves a better classification result if scaling is turned on + @param useNullRejection: sets if a predicted class will be rejected if the classes' probability is below the classificationThreshold + @param useAutoGamma: sets if the SVM gamma parameter will automatically be computed, if set to true then gamma will be set to (1.0/numFeatures), where numFeatures is the number of features in the training data + @param gamma: sets the SVM gamma parameter + @param degree: sets the SVM degree parameter + @param coef0: sets the SVM coef0 parameter + @param nu: sets the SVM nu parameter + @param C: sets the SVM C parameter + @param useCrossValidation: sets if the SVM model will be trained using cross validation + @param kFoldValue: sets the number of folds that will be used for cross validation + @return returns true if the SVM was initialized, false otherwise + */ + bool init(KernelType kernelType,SVMType svmType,bool useScaling,bool useNullRejection,bool useAutoGamma, + float gamma, + unsigned int degree, + float coef0, + float nu, + float C, + bool useCrossValidation, + unsigned int kFoldValue + ); + + int getNumInputs() const; + std::vector<int> getWhichInputs() const; + + +#ifndef EMSCRIPTEN + void getJSONDescription(Json::Value ¤tModel); +#endif + +private: + bool problemSet; + struct LIBSVM::svm_model *model; + struct LIBSVM::svm_parameter param; + struct LIBSVM::svm_problem problem; + + int numInputs; + + /** Normalization parameters */ + std::vector<double> inRanges; + std::vector<double> inBases; + + bool trained; +}; + +#endif + + + + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/trainingExample.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/trainingExample.h new file mode 100644 index 0000000000000000000000000000000000000000..ac9c3f19f25f48c2116d1966f8f9e1a91f2d4c08 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/trainingExample.h @@ -0,0 +1,38 @@ +/** + * @file trainingExample.h + * RapidLib + * + * @author Michael Zbyszynski + * @date 22 Nov 2017 + * @copyright Copyright © 2016 Goldsmiths. All rights reserved. + */ + +#ifndef trainingExample_h +#define trainingExample_h + +#include <vector> +#include <string> + +/** This is used by both NN and KNN models for training */ +template<typename T> +struct trainingExampleTemplate { + std::vector<T> input; + std::vector<T> output; +}; + +//This is here to keep the old API working +using trainingExample = trainingExampleTemplate<double>; +using trainingExampleFloat = trainingExampleTemplate<float>; + +/** This is used by DTW models for training */ +template<typename T> +struct trainingSeriesTemplate { + std::vector<std::vector<T> > input; + std::string label; +}; + +//This is here to keep the old API working +using trainingSeries = trainingSeriesTemplate<double> ; +using trainingSeriesFloat = trainingSeriesTemplate<float>; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/warpPath.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/warpPath.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1768dc17c0e81f9474af5f524c2328fa616d1b2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/warpPath.cpp @@ -0,0 +1,18 @@ +/** + * @file warpPath.cpp + * RapidLib + * @author Michael Zbyszysnski + * @date 13 Sep 2017 + * + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include "warpPath.h" + +warpPath::warpPath() {}; +warpPath::~warpPath() {}; + +void warpPath::add(int x, int y) { + xIndices.insert(xIndices.begin(), x); + yIndices.insert(yIndices.begin(), y); +}; diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/warpPath.h b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/warpPath.h new file mode 100644 index 0000000000000000000000000000000000000000..906123aaa8ce1bd2dc17ff42dbcec24dff5e2a21 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/RapidLib/src/warpPath.h @@ -0,0 +1,37 @@ +/** + * @file warpPath.h + * RapidLib + * @author Michael Zbyszynski + * @date 13 Sep 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#ifndef warpPath_h +#define warpPath_h + +#include <vector> + +/** Class to hold warp paths through a cost matrix */ +class warpPath { +public: + warpPath(); + ~warpPath(); + /** + * Add a point to the beginning of the warp path. + * (Paths are calculated starting from the end) + */ + void add(int x, int y); + + std::vector<int> xIndices; + std::vector<int> yIndices; +}; + +/** return struct holding a warp path and the cost of that path */ +struct warpInfo { +public: + warpPath path; + double cost; + +}; + +#endif /* warpPath_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/.gitignore b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..62d8ccb57e174efbbcd08c27ea43919735ae4800 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/.gitignore @@ -0,0 +1,14 @@ +**/.DS_Store +**/xcuserdata/** + +**/CMakeLists.txt + +src/host/PiPoHost.cpp + +build/doxygen/pipo-long.doxygen +build/doxygen/pipo-original.doxygen +build/doxygen/pipo-sdk.doxygen + +doc/pipo-sdk.doxygen +doc/pipo_long.doxygen +doc/html/** diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/README.md b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/README.md new file mode 100644 index 0000000000000000000000000000000000000000..db55481e3f058b217cfb317bc03559b2312fecf5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/README.md @@ -0,0 +1,103 @@ + +# PiPo — Plugin Interface for Processing Objects # + +PiPo is an extremely simple plugin API for modules processing streams of multi-dimensional data such as audio, audio descriptors, or gesture and motion data. The current version of the interface is limited to unary operations. Each PiPo module receives and produces a single stream. The elements of a stream are time-tagged or regularly sampled scalars, vectors, or two-dimensional matrices. + + +### More Information + +http://ismm.ircam.fr/pipo/ + +### Authors + +This code has been initially authored by Norbert Schnell in the <a href="http://ismm.ircam.fr">Sound Music Movement Interaction</a> team of the <a href="http://www.ircam.fr/stms.html?&L=1">STMS Lab</a> - IRCAM - CNRS - UPMC. + +### Copyright + +Copyright (c) 2012–2017 by IRCAM – Centre Pompidou, Paris, France. +All rights reserved. + +### Licence: BSD 3-clause + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +- Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### Features + +PiPo has been developed to make things simple for users and developers. + +#### User Level Features + +- Easy integration and customization of stream processing modules +- Suited for filtering, transformation, extraction, and segmentation algorithms +- Real-time and offline processing +- Applying to audio and control streams (for whom this distinction still makes sense) + +#### Developer Level Features + +- Fast and easy implementation of modules and reuse of code for different contexts +- C/C++ API defined by a single header file without additional dependencies +- Core API as single abstract class defining a small set of virtual methods + +#### PiPo Stream Attributes + +PiPo streams are a sequences of frames characterized by a set of attributes. A PiPo module defines the attributes of its output stream when receiving the attributes of the input stream. + +Each module can configure its internal state depending on the attributes of the input stream (e.g. memory allocation and pre-calculated state variables) before propagating its output stream attributes to the next module. + +This way, the attributes of the input stream are propagated through a series of PiPo modules before starting the actual stream processing. + +In summary, a PiPo stream is described by the following attributes: + +- a boolean representing whether the elements of the stream are time-tagged +- frame rate (highest average rate for time-tagged streams) +- lag of the output stream relative to the input +- frame width (also number of channels or matrix columns) +- frame height (or number of matrix rows) +- labels (for the frame channels or columns) +- a boolean representing whether the frames have a variable size (respecting the given frame size as maximum) +- extent of a frame in the given domain (e.g. duration or frequency range) +- maximum number of frames in a block exchanged between two modules + +#### PiPo Module Parameters + +The PiPo SDK comes with a template class [PiPo::Attr](http://recherche.ircam.fr/equipes/temps-reel/mubu/pipo/sdk-doc-v0.1/class_pi_po_1_1_attr.html) permits to define scalar, enum, or variable or fixed size vector attributes of a pipo module that are exposed to the host environment. + +Since certain parameter changes may also change the attributes of a module’s output stream, PiPo provides a mechanism for signaling these changes through the following modules to the processing environment (i.e. the PiPo host). + +For MAX/MSP PiPo includes a binding to extend a PiPo class to a Max/MSP external that then declares the module's parameters as Max/MSP attributes and implement the required setters and getters. + +## PiPo API + +### Module API + +The PiPo Module API consists of the abstract class [PiPo](http://recherche.ircam.fr/equipes/temps-reel/mubu/pipo/sdk-doc-v0.1/class_pi_po.html) in [PiPo.h](src/include/PiPo.h) of a few virtual methods for propagating stream attributes (see above), frames, and additional processing control through a series of modules: + +- Propagating stream attributes +- Propagating frames +- Reset stream processing +- Finalize stream processing +- Propagate the change of a parameter requiring redefining the output stream attributes + +See the doc extraced from [PiPo.h](include/PiPo.h) at: http://recherche.ircam.fr/equipes/temps-reel/mubu/pipo/sdk-doc-v0.1/ + +### Host API + +Classes supporting implementation of PiPo hosts are found in directory [host](src/host). + +PiPo comes with a collection of native modules that can be combined into graphs to form more complex modules. +Their source code is located into directory [modules](src/modules). + +The host-level `PiPoCollection` class is a module factory, able to instantiate complex PiPo modules from a simple graph syntax. +It provides all the native PiPo modules and can be extended with third-party PiPo modules, thus allowing to create a wide number +of combinations. + + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/bin/osx/libpipo.a b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/bin/osx/libpipo.a new file mode 100644 index 0000000000000000000000000000000000000000..d69bcde24506e11955ddf3b4da27858fe95094db Binary files /dev/null and b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/bin/osx/libpipo.a differ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/BayesianFilter.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/BayesianFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..408de51d0c32cf08d201ba3fcd72c6a421e954fd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/BayesianFilter.cpp @@ -0,0 +1,155 @@ +/** + * @file BayesianFilter.cpp + * @author Jules Francoise + * @date 24.12.2013 + * + * Non-linear Baysian filtering for EMG Enveloppe Extraction. + * Based on Matlab code by Terence Sanger : kidsmove.org/bayesemgdemo.html + * + * Reference: + * - Sanger, T. (2007). Bayesian filtering of myoelectric signals. Journal of neurophysiology, 1839–1845. + * + * @copyright + * Copyright (C) 2013-2014 by IRCAM - Centre Pompidou. + * All Rights Reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BayesianFilter.h" +#include "filter_utilities.h" + + +#pragma mark - +#pragma mark Constructors +BayesianFilter::BayesianFilter() +{ + mvc.assign(channels, 1.); + init(); +} + +BayesianFilter::~BayesianFilter() +{ + +} + +void BayesianFilter::resize(std::size_t size) +{ + if (size > 0) { + channels = size; + init(); + } +} + +std::size_t BayesianFilter::size() const +{ + return channels; +} + +#pragma mark - +#pragma mark Main Algorithm +void BayesianFilter::init() +{ + mvc.resize(channels, 1.); + output.assign(channels, 0.); + prior.resize(channels); + state.resize(channels); + g.resize(channels); + for (unsigned int i=0; i<channels; i++) { + prior[i].resize(levels); + state[i].resize(levels); + g[i].resize(3); + + double val(1.); + for (unsigned int t=0; t<levels; t++) { + state[i][t] = val * mvc[i] / double(levels); + val += 1; + prior[i][t] = 1. / levels; + } + + double diff = diffusion * diffusion / (samplerate * std::pow(mvc[i] / levels, 2)); + g[i][0] = diff / 2.; + g[i][1] = 1. - diff - this->jump_rate; + g[i][2] = diff / 2.; + } +} + +void BayesianFilter::update(vector<float> const& observation) +{ + if (observation.size() != this->channels) { + resize(observation.size()); + } + + for (std::size_t i=0; i<channels; i++) + { + // -- 1. Propagate + // ----------------------------------------- + + vector<double> a(1, 1.); + vector<double> oldPrior(prior[i].size()); + // oldPrior.swap(prior[i]); + copy(prior[i].begin(), prior[i].end(), oldPrior.begin()); + + filtfilt(g[i], a, oldPrior, prior[i]); + + // set probability of a sudden jump + for (unsigned int t=0; t<levels; t++) { + prior[i][t] = prior[i][t] + jump_rate / mvc[i]; + } + + // -- 4. Calculate the posterior likelihood function + // ----------------------------------------- + // calculate posterior density using Bayes rule + vector<double> posterior(levels); + double sum_posterior(0.); + for (unsigned int t=0; t<levels; t++) { + double x_2 = state[i][t] * state[i][t]; + posterior[t] = this->prior[i][t] * exp(- observation[i] * observation[i] / x_2) / x_2; + sum_posterior += posterior[t]; + } + + // -- 5. Output the signal estimate output(x(t)) = argmax P(x,t); + // ----------------------------------------- + // find the maximum of the posterior density + unsigned int pp(0); + double tmpMax(posterior[0]); + for (unsigned int t=0; t<levels; t++) { + if (posterior[t] > tmpMax) { + tmpMax = posterior[t]; + pp = t; + } + posterior[t] /= sum_posterior; + } + + // convert index of peak value to scaled EMG value + output[i] = state[i][pp] / mvc[i]; + + // -- 7. Repeat from step 2 > prior for next iteration is posterior from this iteration + // ----------------------------------------- + copy(posterior.begin(), posterior.end(), prior[i].begin()); + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/BayesianFilter.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/BayesianFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..3f97d3f450a05cda5ba29b146a2d1d61bede99de --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/BayesianFilter.h @@ -0,0 +1,183 @@ +/** + * @file BayesianFilter.h + * @author Jules Francoise + * @date 24.12.2013 + * + * Non-linear Baysian filtering for EMG Enveloppe Extraction. + * Based on Matlab code by Terence Sanger : kidsmove.org/bayesemgdemo.html + * + * Reference: + * - Sanger, T. (2007). Bayesian filtering of myoelectric signals. Journal of neurophysiology, 1839–1845. + * + * @copyright + * Copyright (C) 2013-2014 by IRCAM - Centre Pompidou. + * All Rights Reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __emg_bayesfilter__BayesianFilter__ +#define __emg_bayesfilter__BayesianFilter__ + +#include <algorithm> +#include <iostream> +#include <cmath> +#include <vector> + +using namespace std; + +/*! + @mainpage + # Bayesian Filtering for EMG envelope extraction + + Non-linear baysian filter. + Code is based on Matlab example code from Terence Sanger, available at [kidsmove.org/bayesemgdemo.html](kidsmove.org/bayesemgdemo.html) + + ## Reference: + * Sanger, T. (2007). __Bayesian filtering of myoelectric signals.__ _Journal of neurophysiology_, 1839–1845. + + ## Contact + @copyright Copyright (C) 2012-2014 by IRCAM. All Rights Reserved. + @author Jules Francoise - Ircam - jules.francoise@ircam.fr + @date 2013-12-26 + + */ + +/*! + @class BayesianFilter + @brief Main class for non-linear Bayesian fitering + + @copyright Copyright 2013 Ircam - Jules Francoise. All Rights Reserved. + @author Jules Francoise - Ircam - jules.francoise@ircam.fr + @date 2013-12-26 + */ +class BayesianFilter { +public: +#pragma mark - +#pragma mark Public attributes + vector<float> output; //<! bayes estimates + +#pragma mark - +#pragma mark Constructors + /*! + Constructor + @param _samplerate Sampling frequency of input stream + @param _clipping Signal Clipping + @param _alpha Diffusion rate + @param _beta Probability of sudden jumps + @param _levels number of output levels + @param _rectification signal rectification + */ + BayesianFilter(); + + ~BayesianFilter(); + + void resize(std::size_t size); + std::size_t size() const; + +#pragma mark - +#pragma mark Main Algorithm + /*! + @brief Initialize filter + Resets Prior to uniform distribution + */ + void init(); + + /*! + @brief Update filter state and compute prediction. + + The output of the system (envelope estimated by Maximum A Posteriori) is stored in the public member output + @param observation observation (input) vector + */ + void update(vector<float> const& observation); + +#pragma mark - +#pragma mark Python +#ifdef SWIGPYTHON + void update(int _inchannels, double *observation, int _outchannels, double *_output) + { + vector<float> observation_vec(_inchannels); + for (unsigned int t=0; t<_inchannels; t++) + observation_vec[t] = float(observation[t]); + + this->update(observation_vec); + + for (unsigned int t=0; t<_inchannels; t++) + _output[t] = double(this->output[t]); + } +#endif + + /** + @brief Maximum Value contraction (estimated using Standard deviation on isometric max contraction) + */ + std::vector<double> mvc; + + /** + @brief Number of output levels + */ + unsigned int levels = 100; + + /** + @brief Sampling frequency + */ + double samplerate = 200.; + + /** + @brief Diffusion rate (typically 1e-9 <> 1e-1) + */ + double diffusion = 0.1; + + /** + @brief Probability of sudden jumps (typically 1e-24 <> 1e-1) + */ + double jump_rate = 0.1; + +protected: + /** + @brief Number of input channels + */ + std::size_t channels = 1; + + /** + @brief Latent variable (the driving rate) + */ + vector< vector<double> > state; + + /** + @brief Prior + */ + vector< vector<double> > prior; + + /** + @brief Approximate spatial second derivative operator + */ + vector< vector<double> > g; +}; + + +#endif + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/filter_utilities.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/filter_utilities.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fb0700512bdc3964aa060d8722f86ad6c33f0d3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/filter_utilities.cpp @@ -0,0 +1,200 @@ +/** + * @file filter_utilities.cpp + * @author Jules Francoise + * @date 24.12.2013 + * contact: jules.francoise@ircam.fr + * + * @brief Filtering utilities + * + * c++ implementations of scipy.signal standard filtering functions + * + * @copyright + * Copyright (C) 2013-2014 by IRCAM - Centre Pompidou. + * All Rights Reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "filter_utilities.h" + +void filtfilt(vector<double> const& b, vector<double> const& a, vector<double> & x, vector<double> & y, PADTYPE padtype, int padlen) +{ + int ntaps = max(a.size(), b.size()); + + if (padtype == NONE) + padlen=0; + unsigned int edge; + if (padlen < 0) + edge = ntaps * 3; + else + edge = padlen; + + if (x.size() <= edge) + throw runtime_error("The length of the input vector x must be at least padlen."); + + vector<double> ext; + if (padtype != NONE && edge > 0) { + // Make an extension of length 'edge' at each + // end of the input array. + switch (padtype) { + case EVEN: + even_ext<double>(x, ext, edge); + break; + case ODD: + odd_ext<double>(x, ext, edge); + break; + default: + const_ext<double>(x, ext, edge); + } + } else { + ext = x; + } + + // Get the steady state of the filter's step response. + vector<double> zi; + lfilter_zi(b, a, zi); + + // Forward filter. + y.resize(ext.size()); + vector<double> zip = zi; + for (unsigned int i=0 ; i<zi.size(); i++) { + zip[i] = zi[i] * x[0]; + } + + vector<double> y_reverse(ext.size()); + lfilter(b, a, ext, y_reverse, zip); + + reverse_copy(y_reverse.begin(), y_reverse.end(), y.begin()); + + // Backward filter. + // Create y0 so zi*y0 broadcasts appropriately. + for (unsigned int i=0 ; i<zip.size(); i++) { + zip[i] = zi[i] * x[x.size()-1]; + } + lfilter(b, a, y, y_reverse, zip); + + // Reverse y. + y.resize(x.size()); + reverse_copy(y_reverse.begin()+edge, y_reverse.end()-edge, y.begin()); +} + + +void lfilter(vector<double> const& b, vector<double> const& a, vector<double> const& x, vector<double> & y, vector<double> const& zi) +{ + vector<double> _b = b; + vector<double> _a = a; + + // Pad a or b with zeros so they are the same length. + unsigned int k = max(a.size(), b.size()); + + if (_a.size() < k) + _a.resize(k, 0.); + else if (_b.size() < k) + _b.resize(k, 0.); + + if (_a[0] != 1.0) { + // Normalize the coefficients so a[0] == 1. + for (unsigned int i=0; i<k; i++) { + _a[i] /= _a[0]; + _b[i] /= _a[0]; + } + } + + vector<double> z = zi; + unsigned int n = x.size(); + y.resize(n); + for (unsigned int m=0; m<n; m++) { + y[m] = _b[0] * x[m] + z[0]; + for (unsigned int i=0; i<k-2; i++) { + z[i] = _b[i+1] * x[m] + z[i+1] - _a[i+1] * y[m]; + } + z[k-2] = _b[k-1] * x[m] - _a[k-1] * y[m]; + } +} + + +void lfilter_zi(vector<double> const& b, vector<double> const& a, vector<double> & zi) { + vector<double> _b = b; + vector<double> _a = a; + + if (_a[0] != 1.0) { + // Normalize the coefficients so a[0] == 1. + for (unsigned int i=0; i<_a.size(); i++) { + _a[i] /= _a[0]; + _b[i] /= _a[0]; + } + } + + unsigned int n = max(_a.size(), _b.size()); + + // Pad a or b with zeros so they are the same length. + if (_a.size() < n) + _a.resize(n, 0.); + else if (_b.size() < n) + _b.resize(n, 0.); + + vector<double> IminusA((n-1)*(n-1), 0.); + for (unsigned int i=0; i<n-1; i++) { + IminusA[i*(n-1)+i] = 1.; + } + + vector<double> companion((n-1)*(n-1), 0.); + for (unsigned int i=0; i<n-1; i++) { + companion[i] = -_a[i+1] / (1.0 * _a[0]); + } + for (unsigned int i=1; i<n-1; i++) { + companion[i*(n-1)+i-1] = 1.; + } + + for (unsigned int i=0; i<n-1; i++) { + for (unsigned int j=0; j<n-1; j++) { + IminusA[i*(n-1)+j] -= companion[j*(n-1)+i]; + } + } + + zi.clear(); + zi.resize(n - 1, 0.); + + double tmpSum(0.); + for (unsigned int i=0; i<n-1; i++) { + zi[0] += _b[i+1] - _a[i+1] * _b[0]; + tmpSum += IminusA[i*(n-1)]; + } + zi[0] /= tmpSum; + + // TODO: remove B + + // Solve zi = A*zi + B + double asum = 1.0; + double csum = 0.0; + for (unsigned int k=1; k<n-1; k++) { + asum += _a[k]; + csum += _b[k] - _a[k]*_b[0]; + zi[k] = asum*zi[0] - csum; + } +} + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/filter_utilities.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/filter_utilities.h new file mode 100644 index 0000000000000000000000000000000000000000..f72e99e8a57e827f747953fc459389f328790425 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/bayesfilter/filter_utilities.h @@ -0,0 +1,138 @@ +/** + * @file filter_utilities.h + * @author Jules Francoise + * @date 24.12.2013 + * contact: jules.francoise@ircam.fr + * + * @brief Filtering utilities + * + * c++ implementations of scipy.signal standard filtering functions + * + * @copyright + * Copyright (C) 2013-2014 by IRCAM - Centre Pompidou. + * All Rights Reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __emg_bayesfilter__filter_utilities__ +#define __emg_bayesfilter__filter_utilities__ + +#include <algorithm> +#include <iostream> +#include <exception> +#include <stdexcept> +#include <vector> + +using namespace std; + +typedef enum _padtype { + EVEN, + ODD, + CONSTANT, + NONE +} PADTYPE; + +void filtfilt(vector<double> const& b, vector<double> const& a, vector<double> & x, vector<double> & y, PADTYPE padtype = ODD, int padlen=-1); +void lfilter_zi(vector<double> const& b, vector<double> const& a, vector<double> & zi); +void lfilter(vector<double> const& b, vector<double> const& a, vector<double> const& x, vector<double> & y, vector<double> const& zi); + +/*! + 1D python-like even_ext function. + + */ +template <typename datatype> +void even_ext(vector<datatype> const& src, vector<datatype> & dst, unsigned int n) +{ + if (n<1) + dst = src; + if (n > src.size() - 1) + throw runtime_error("The extension length n is too big. It must not exceed src.size()-1."); + + dst.resize(2 * n + src.size()); + + int t(0); + for (int i=n; i>0; i--) { + dst[t++] = src[i]; + } + copy(src.begin(), src.end(), dst.begin()+n); + + t += src.size(); + for (unsigned int i=src.size()-2; i>src.size()-n-2; i--) { + dst[t++] = src[i]; + } +} + +// 1D python-like odd_ext +template <typename datatype> +void odd_ext(vector<datatype> const& src, vector<datatype> & dst, unsigned int n) +{ + if (n<1) + dst = src; + if (n > src.size() - 1) + throw runtime_error("The extension length n is too big. It must not exceed src.size()-1."); + + dst.resize(2 * n + src.size()); + + int t(0); + for (int i=n; i>0; i--) { + dst[t++] = 2 * src[0] - src[i]; + } + copy(src.begin(), src.end(), dst.begin()+n); + + t += src.size(); + for (unsigned int i=src.size()-2; i>src.size()-n-2; i--) { + dst[t++] = 2 * src[src.size()-1] - src[i]; + } +} + +// 1D python-like const_ext +template <typename datatype> +void const_ext(vector<datatype> const& src, vector<datatype> & dst, unsigned int n) +{ + if (n<1) + dst = src; + if (n > src.size() - 1) + throw runtime_error("The extension length n is too big. It must not exceed src.size()-1."); + + dst.resize(2 * n + src.size()); + + int t(0); + for (int i=n; i>0; i--) { + dst[t++] = src[0]; + } + copy(src.begin(), src.end(), dst.begin()+n); + + t += src.size(); + for (unsigned int i=src.size()-2; i>src.size()-n-2; i--) { + dst[t++] = src[src.size()-1]; + } +} + + +#endif + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/finitedifferences/finitedifferences.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/finitedifferences/finitedifferences.c new file mode 100644 index 0000000000000000000000000000000000000000..e80f70d1e44aa9616e571833dc7cbfc79d332d5e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/finitedifferences/finitedifferences.c @@ -0,0 +1,265 @@ +/** + * @file finitedifferences.c + * @author gael.dubus@ircam.fr + * + * Largely inspired by rta_delta.c + * + * @copyright + * Copyright (C) 2016 by ISMM IRCAM - Centre Pompidou, Paris, France + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "finitedifferences.h" +//#include "rta_math.h" + + +int finitedifferences_weights_by_filtersize(float * weights_vector, const int derivative_order, const unsigned int filter_size, const enum FDMethod method){ + unsigned int i; + float factor; + switch (method){ + case Backward: + factor = 1./FDBackward[derivative_order-1][filter_size-derivative_order-1][2]; + for (i=0; i<filter_size; i++){ + weights_vector[i] = FDBackward[derivative_order-1][filter_size-derivative_order-1][i+3]*factor; + } + break; + case Centered: + factor = 1./FDCentered[derivative_order-1][(filter_size-derivative_order+1)/2-1][2]; + for (i=0; i<filter_size; i++){ + weights_vector[i] = FDCentered[derivative_order-1][(filter_size-derivative_order+1)/2-1][i+3]*factor; + } + break; + case Forward: + factor = 1./FDForward[derivative_order-1][filter_size-derivative_order-1][2]; + for (i=0; i<filter_size; i++){ + weights_vector[i] = FDForward[derivative_order-1][filter_size-derivative_order-1][i+3]*factor; + } + default: + break; + } + return 1; +} + +int finitedifferences_weights_by_accuracy(float * weights_vector, const int derivative_order, const int accuracy_order, const enum FDMethod method){ + int i; + float factor; + switch (method){ + case Backward: + factor = 1./FDBackward[derivative_order-1][accuracy_order-1][2]; + for (i=0; i<accuracy_order+derivative_order; i++){ + weights_vector[i] = FDBackward[derivative_order-1][accuracy_order-1][i+3]*factor; + } + break; + case Centered: + factor = 1./FDCentered[derivative_order-1][accuracy_order/2-1][2]; + //This stands for a centered FD: stencil_size = accuracy_order+2*(derivative_order-derivative_order/2)-1 + //one could also use: stencil_size = FDCentered[derivative_order-1][accuracy_order/2-1][0] + for (i=0; i<accuracy_order+2*(derivative_order-derivative_order/2)-1; i++){ + weights_vector[i] = FDCentered[derivative_order-1][accuracy_order/2-1][i+3]*factor; + } + break; + case Forward: + factor = 1./FDForward[derivative_order-1][accuracy_order-1][2]; + for (i=0; i<accuracy_order+derivative_order; i++){ + weights_vector[i] = FDForward[derivative_order-1][accuracy_order-1][i+3]*factor; + } + default: + break; + } + return 1; +} + +/* +int finitedifferences_weights_by_size_stride(float * weights_vector, const int w_stride, const unsigned int filter_size, const enum FDMethod method, const int accuracy_order){ + int i; + float filter_value; + + + + //const rta_real_t half_filter_size = rta_floor(filter_size * 0.5); + + / *for(i=0, filter_value=-half_filter_size; + i<filter_size*w_stride; + i+=w_stride, filter_value+=1.) + { + weights_vector[i] = filter_value; + }* / + + return 1; +} +*/ + +/* +float finitedifferences_normalization_factor(const unsigned int filter_size, const enum FDMethod method, const int accuracy_order) +{ + float normalization = 0.; + if (filter_size > 0){ + int i; + const int half_filter_size = filter_size / 2; + + for(i=1; i<=half_filter_size; i++) + { + normalization += (float) (i*i); + } + + normalization = 0.5 / normalization; + } + return normalization; + } + +*/ + +void finitedifferences(float * output, const float * input_vector, const float * weights_vector, const unsigned int filter_size){ + unsigned int i; + *output = 0.; + + for(i=0; i<filter_size; i++){ + if(weights_vector[i] != 0.){ + *output += input_vector[i] * weights_vector[i]; + } + } + return; +} + +/* +void finitedifferences_stride(float * delta, + const float * input_vector, const int i_stride, + const float * weights_vector, const int w_stride, + const unsigned int filter_size) +{ + unsigned int i; + + *delta = 0.; + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i*w_stride] != 0.) + { + *delta += input_vector[i*i_stride] * weights_vector[i*w_stride]; + } + } + + return; +} +*/ + + +void finitedifferences_vector(float * delta, + const float * input_matrix, const unsigned int input_size, + const float * weights_vector, const unsigned int filter_size) +{ + unsigned int i,j; + + for(j=0; j<input_size; j++) + { + delta[j] = 0.; + } + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i] != 0.) /* skip zeros */ + { + for(j=0; j<input_size; j++) + { + delta[j] += input_matrix[i*input_size+j] * weights_vector[i]; + } + } + } + + return; +} + + +/* +void finitedifferences_vector_stride(float * delta, const int d_stride, + const float * input_matrix, const int i_stride, + const unsigned int input_size, + const float * weights_vector, const int w_stride, + const unsigned int filter_size) +{ + int i,j; + + for(j=0; j<input_size*d_stride; j+=d_stride) + { + delta[j] = 0.; + } + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i*w_stride] != 0.) / * skip zeros * / + { + for(j=0; j<input_size; j++) + { + delta[j*d_stride] += input_matrix[(i*input_size+j)*i_stride] * + weights_vector[i*w_stride]; + } + } + } + + return; +} +*/ + +int accuracy_to_filtersize(const enum FDMethod method, const int derivative_order, const int accuracy_order){ + int res; + switch (method){ + case Centered: + res = accuracy_order+2*((derivative_order-1)/2)+1; + break; + case Backward: + case Forward: + res = accuracy_order + derivative_order; + break; + default: + res = 0; + break; + } + return res; +} + +int filtersize_to_accuracy(const enum FDMethod method, const int derivative_order, const unsigned int filter_size){ + int res; + switch (method){ + case Centered: + //res = FDCentered[derivative_order-1][(filter_size-derivative_order+1)/2-1]; + res = filter_size-2*((derivative_order-1)/2)-1; + break; + case Backward: + //res = FDBackward[derivative_order-1][filter_size-derivative_order-1][1]; + //break; + case Forward: + //res = FDForward[derivative_order-1][filter_size-derivative_order-1][1]; + res = filter_size-derivative_order; + break; + default: + res = 0; + break; + } + return res; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/finitedifferences/finitedifferences.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/finitedifferences/finitedifferences.h new file mode 100644 index 0000000000000000000000000000000000000000..40da4fc8ae8f323af2996805457e8663b92893eb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/finitedifferences/finitedifferences.h @@ -0,0 +1,167 @@ +/** + * @file finitedifferences.h + * @author gael.dubus@ircam.fr + * + * Largely inspired by rta_delta.h + * + * @copyright + * Copyright (C) 2016 by ISMM IRCAM - Centre Pompidou, Paris, France + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FINITEDIFFERENCES_H_ +#define _FINITEDIFFERENCES_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + + +enum FDMethod {Backward, Centered, Forward}; + + + /* + Structure of the tables: + FDBackward[derivative_order][stencil_order] = [stencil_size, accuracy_order, 1/factor, [coefficients]] + */ + + //Name format: B`derivative_order``stencil_size` + static const int B12[5] = {2, 1, 1, -1, 1}; //array size = array[0]+3 + static const int B13[6] = {3, 2, 2, 1, -4, 3}; + static const int B14[7] = {4, 3, 6, -2, 9, -18, 11}; + static const int B15[8] = {5, 4, 12, 3, -16, 36, -48, 25}; + static const int B16[9] = {6, 5, 60, -12, 75, -200, 300, -300, 137}; + static const int B17[10] = {7, 6, 60, 10, -72, 225, -400, 450, -360, 147}; + static const int B23[6] = {3, 1, 1, 1, -2, 1}; + static const int B24[7] = {4, 2, 1, -1, 4, -5, 2}; + static const int B25[8] = {5, 3, 12, 11, -56, 114, -104, 35}; + static const int B26[9] = {6, 4, 12, -10, 61, -156, 214, -154, 45}; + static const int B27[10] = {7, 5, 180, 137, -972, 2970, -5080, 5265, -3132, 812}; + static const int B28[11] = {8, 6, 180, -126, 1019, -3618, 7380, -9490, 7911, -4014, 938}; + static const int B34[7] = {4, 1, 1, -1, 3, -3, 1}; + static const int B35[8] = {5, 2, 2, 3, -14, 24, -18, 5}; + static const int B36[9] = {6, 3, 4, -7, 41, -98, 118, -71, 17}; + static const int B37[10] = {7, 4, 8, 15, -104, 307, -496, 461, -232, 49}; + static const int B38[11] = {8, 5, 120, -232, 1849, -6432, 12725, -15560, 11787, -5104, 967}; + static const int B39[12] = {9, 6, 120, 469, -4216, 16830, -39128, 58280, -57384, 36706, -13960, 2403}; + static const int B45[8] = {5, 1, 1, 1, -4, 6, -4, 1}; + static const int B46[9] = {6, 2, 1, -2, 11, -24, 26, -14, 3}; + static const int B47[10] = {7, 3, 6, 17, -114, 321, -484, 411, -186, 35}; + static const int B48[11] = {8, 4, 6, -21, 164, -555, 1056, -1219, 852, -333, 56}; + static const int B49[12] = {9, 5, 240, 967, -8576, 33636, -76352, 109930, -102912, 61156, -21056, 3207}; + //Name format: B`derivative_order` + static const int *B1[6] = {B12, B13, B14, B15, B16, B17}; + static const int *B2[6] = {B23, B24, B25, B26, B27, B28}; + static const int *B3[6] = {B34, B35, B36, B37, B38, B39}; + static const int *B4[5] = {B45, B46, B47, B48, B49}; + static const int **FDBackward[4] = {B1, B2, B3, B4}; + //To get the right one: FDBackward[derivative_order-1][stencil_size-derivative_order-1] + + //Forward FD + static const int F12[5] = {2, 1, 1, -1, 1}; + static const int F13[6] = {3, 2, 2, -3, 4, -1}; + static const int F14[7] = {4, 3, 6, -11, 18, -9, 2}; + static const int F15[8] = {5, 4, 12, -25, 48, -36, 16, -3}; + static const int F16[9] = {6, 5, 60, -137, 300, -300, 200, -75, 12}; + static const int F17[10] = {7, 6, 60, -147, 360, -450, 400, -225, 72, -10}; + static const int F23[6] = {3, 1, 1, 1, -2, 1}; + static const int F24[7] = {4, 2, 1, 2, -5, 4, -1}; + static const int F25[8] = {5, 3, 12, 35, -104, 114, -56, 11}; + static const int F26[9] = {6, 4, 12, 45, -154, 214, -156, 61, -10}; + static const int F27[10] = {7, 5, 180, 812, -3132, 5265, -5080, 2970, -972, 137}; + static const int F28[11] = {8, 6, 180, 938, -4014, 7911, -9490, 7380, -3618, 1019, -126}; + static const int F34[7] = {4, 1, 1, -1, 3, -3, 1}; + static const int F35[8] = {5, 2, 2, -5, 18, -24, 14, -3}; + static const int F36[9] = {6, 3, 4, -17, 71, -118, 98, -41, 7}; + static const int F37[10] = {7, 4, 8, -49, 232, -461, 496, -307, 104, -15}; + static const int F38[11] = {8, 5, 120, -967, 5104, -11787, 15560, -12725, 6432, -1849, 232}; + static const int F39[12] = {9, 6, 240, -2403, 13960, -36706, 57384, -58280, 39128, -16830, 4216, -469}; + static const int F45[8] = {5, 1, 1, 1, -4, 6, -4, 1}; + static const int F46[9] = {6, 2, 1, 3, -14, 26, -24, 11, -2}; + static const int F47[10] = {7, 3, 6, 35, -186, 411, -484, 321, -114, 17}; + static const int F48[11] = {8, 4, 6, 56, -333, 852, -1219, 1056, -555, 164, -21}; + static const int F49[12] = {9, 5, 240, 3207, -21056, 61156, -102912, 109930, -76352, 33636, -8576, 967}; + static const int *F1[6] = {F12, F13, F14, F15, F16, F17}; + static const int *F2[6] = {F23, F24, F25, F26, F27, F28}; + static const int *F3[6] = {F34, F35, F36, F37, F38, F39}; + static const int *F4[5] = {F45, F46, F47, F48, F49}; + static const int **FDForward[4] = {F1, F2, F3, F4}; + //To get the right one: FDForward[derivative_order-1][stencil_size-derivative_order-1] + + //Centered FD + static const int C13[6] = {3, 2, 2, -1, 0, 1}; + static const int C15[8] = {5, 4, 12, 1, -8, 0, 8, -1}; + static const int C17[10] = {7, 6, 60, -1, 9, -45, 0, 45, -9, 1}; + static const int C19[12] = {9, 8, 840, 3, -32, 168, -672, 0, 672, -168, 32, -3}; + static const int C23[6] = {3, 2, 1, 1, -2, 1}; + static const int C25[8] = {5, 4, 12, -1, 16, -30, 16, -1}; + static const int C27[10] = {7, 6, 180, 2, -27, 270, -490, 270, -27, 2}; + static const int C29[12] = {9, 8, 5040, -9, 128, -1008, 8040, -14350, 8040, -1008, 128, -9}; + static const int C35[8] = {5, 2, 2, -1, 2, 0, -2, 1}; + static const int C37[10] = {7, 4, 8, 1, -8, 13, 0, -13, 8, -1}; + static const int C39[12] = {9, 6, 240, -7, 72, -338, 488, 0, -488, 338, -72, 7}; + static const int C45[8] = {5, 2, 1, 1, -4, 6, -4, 1}; + static const int C47[10] = {7, 4, 6, -1, 12, -39, 56, -39, 12, -1}; + static const int C49[12] = {9, 6, 240, 7, -96, 676, -1952, 2730, -1952, 676, -96, 7}; + static const int C57[10] = {7, 2, 2, -1, 4, -5, 0, 5, -4, 1}; + static const int C67[10] = {7, 2, 1, 1, -6, 15, -20, 15, -6, 1}; + static const int *C1[4] = {C13, C15, C17, C19}; + static const int *C2[4] = {C23, C25, C27, C29}; + static const int *C3[3] = {C35, C37, C39}; + static const int *C4[3] = {C45, C47, C49}; + static const int *C5[1] = {C57}; + static const int *C6[1] = {C67}; + static const int **FDCentered[6] = {C1, C2, C3, C4, C5, C6}; + //To get the right one: FDCentered[derivative_order-1][(stencil_size-derivative_order+1)/2-1] + +int finitedifferences_weights_by_filtersize(float * weights_vector, const int derivative_order, const unsigned int filter_size, const enum FDMethod method); + +int finitedifferences_weights_by_accuracy(float * weights_vector, const int derivative_order, const int accuracy_order, const enum FDMethod method); + + //int finitedifferences_weights_stride(float * weights_vector, const int w_stride, const unsigned int filter_size, const enum FDMethod method, const int accuracy_order); + + //float finitedifferences_normalization_factor(const unsigned int filter_size, const enum FDMethod method, const int accuracy_order); + +void finitedifferences(float * output, const float * input_vector, const float * weights_vector, const unsigned int filter_size); + + //void finitedifferences_stride(float * delta, const float * input_vector, const int i_stride, const float * weights_vector, const int w_stride, const unsigned int filter_size); + + void finitedifferences_vector(float * delta, const float * input_matrix, const unsigned int input_size, const float * weights_vector, const unsigned int filter_size); + + //void finitedifferences_vector_stride(float * delta, const int d_stride, const float * input_matrix, const int i_stride, const unsigned int input_size, const float * weights_vector, const int w_stride, const unsigned int filter_size); + + int accuracy_to_filtersize(const enum FDMethod method, const int derivative_order, const int accuracy_order); + int filtersize_to_accuracy(const enum FDMethod method, const int derivative_order, const unsigned int filter_size); + +#ifdef __cplusplus +} +#endif + +#endif /* _FINITEDIFFERENCES_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/bbpr.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/bbpr.cpp new file mode 100755 index 0000000000000000000000000000000000000000..b4e38873d6eb6a765e0e9d288190f30db7d4bf1f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/bbpr.cpp @@ -0,0 +1,352 @@ +/** + * @file bbpr.cpp + * + * Finds all roots of polynomial by first finding quadratic + * factors using Bairstow's method, then extracting roots + * from quadratics. Implements new algorithm for managing + * multiple roots. + * + * @copyright + * Copyright (C) 2002, 2003, C. Bond. + * All rights reserved. + * + * @see http://www.crbond.com/ + */ + +#include <iomanip> +#include <math.h> +#include <stdlib.h> + +#define maxiter 500 +#define minerr 0.0001 + + +// +// Extract individual real or complex roots from list of quadratic factors +// +int roots(double *a,int n,double *wr,double *wi) +{ + double sq,b2,c,disc; + int m,numroots; + + m = n; + numroots = 0; + while (m > 1) { + b2 = -0.5*a[m-2]; + c = a[m-1]; + disc = b2*b2-c; + if (disc < 0.0) { // complex roots + sq = sqrt(-disc); + wr[m-2] = b2; + wi[m-2] = sq; + wr[m-1] = b2; + wi[m-1] = -sq; + numroots+=2; + } + else { // real roots + sq = sqrt(disc); + wr[m-2] = fabs(b2)+sq; + if (b2 < 0.0) wr[m-2] = -wr[m-2]; + if (wr[m-2] == 0) + wr[m-1] = 0; + else { + wr[m-1] = c/wr[m-2]; + numroots+=2; + } + wi[m-2] = 0.0; + wi[m-1] = 0.0; + } + m -= 2; + } + if (m == 1) { + wr[0] = -a[0]; + wi[0] = 0.0; + numroots++; + } + return numroots; +} +// +// Deflate polynomial 'a' by dividing out 'quad'. Return quotient +// polynomial in 'b' and error metric based on remainder in 'err'. +// +void deflate(double *a,int n,double *b,double *quad,double *err) +{ + double r,s; + int i; + + r = quad[1]; + s = quad[0]; + + b[1] = a[1] - r; + + for (i=2;i<=n;i++){ + b[i] = a[i] - r * b[i-1] - s * b[i-2]; + } + *err = fabs(b[n])+fabs(b[n-1]); +} +// +// Find quadratic factor using Bairstow's method (quadratic Newton method). +// A number of ad hoc safeguards are incorporated to prevent stalls due +// to common difficulties, such as zero slope at iteration point, and +// convergence problems. +// +// Bairstow's method is sensitive to the starting estimate. It is possible +// for convergence to fail or for 'wild' values to trigger an overflow. +// +// It is advisable to institute traps for these problems. (To do!) +// + +// look also at http://jean-pierre.moreau.pagesperso-orange.fr/Cplus/bairstow_cpp.txt + +void find_quad(double *a,int n,double *b,double *quad,double *err, int *iter) +{ + double *c,dn,dr,ds,drn,dsn,eps,r,s, o_r, o_s; + + c = new double [n+1]; + c[0] = 1.0; + r = quad[1]; + s = quad[0]; + eps = 1e-15; + *iter = 1; + + double t = 10000000.0; + + do { + //if (*iter > maxiter) break; + /* + if (((*iter) % 200) == 0) { + eps *= 10.0; + } + */ + b[1] = a[1] - r; + c[1] = b[1] - r; + + for (int i=2;i<=n;i++){ + b[i] = a[i] - r * b[i-1] - s * b[i-2]; + c[i] = b[i] - r * c[i-1] - s * c[i-2]; + } + dn=c[n-1] * c[n-3] - c[n-2] * c[n-2]; + drn=b[n] * c[n-3] - b[n-1] * c[n-2]; + dsn=b[n-1] * c[n-1] - b[n] * c[n-2]; + + if (fabs(dn) < 1e-10) { + if (dn < 0.0) dn = -1e-8; + else dn = 1e-8; + } + dr = drn / dn; + ds = dsn / dn; + r += dr; + s += ds; + (*iter)++; + + if ((fabs(dr)+fabs(ds)) < t){ + t = fabs(dr)+fabs(ds); + o_r = r; + o_s = s; + } + + } while ( (fabs(dr)+fabs(ds)) > eps && *iter < maxiter); + quad[0] = o_s; + quad[1] = o_r; + *err = t; + delete [] c; + return; +} + + +// +// Differentiate polynomial 'a' returning result in 'b'. +// +void diff_poly(double *a,int n,double *b) +{ + double coef; + int i; + + coef = (double)n; + b[0] = 1.0; + for (i=1;i<n;i++) { + b[i] = a[i]*((double)(n-i))/coef; + } +} +// +// Attempt to find a reliable estimate of a quadratic factor using modified +// Bairstow's method with provisions for 'digging out' factors associated +// with multiple roots. +// +// This resursive routine operates on the principal that differentiation of +// a polynomial reduces the order of all multiple roots by one, and has no +// other roots in common with it. If a root of the differentiated polynomial +// is a root of the original polynomial, there must be multiple roots at +// that location. The differentiated polynomial, however, has lower order +// and is easier to solve. +// +// When the original polynomial exhibits convergence problems in the +// neighborhood of some potential root, a best guess is obtained and tried +// on the differentiated polynomial. The new best guess is applied +// recursively on continually differentiated polynomials until failure +// occurs. At this point, the previous polynomial is accepted as that with +// the least number of roots at this location, and its estimate is +// accepted as the root. +// +void recurse(double *a,int n,double *b,int m,double *quad, + double *err,int *iter) +{ + double *c,*x,rs[2],tst; + + if (fabs(b[m]) < 1e-16) m--; // this bypasses roots at zero + if (m == 2) { + quad[0] = b[2]; + quad[1] = b[1]; + *err = 0; + *iter = 0; + return; + } + c = new double [m+1]; + x = new double [n+1]; + c[0] = x[0] = 1.0; + rs[0] = quad[0]; + rs[1] = quad[1]; + *iter = 0; + find_quad(b,m,c,rs,err,iter); + tst = fabs(rs[0]-quad[0])+fabs(rs[1]-quad[1]); + if (*err < 1e-12) { + quad[0] = rs[0]; + quad[1] = rs[1]; + } +// tst will be 'large' if we converge to wrong root + if (((*iter > 5) && (tst < 1e-4)) || ((*iter > 20) && (tst < 1e-1))) { + diff_poly(b,m,c); + recurse(a,n,c,m-1,rs,err,iter); + quad[0] = rs[0]; + quad[1] = rs[1]; + } + delete [] x; + delete [] c; +} +// +// Top level routine to manage the determination of all roots of the given +// polynomial 'a', returning the quadratic factors (and possibly one linear +// factor) in 'x'. +// +void get_quads(double *a,int n,double *quad,double *x) +{ + double *b, *z, err, tmp; + int iter, m; + + if ((tmp = a[0]) != 1.0) { + a[0] = 1.0; + for (int i=1; i<=n; i++) { + a[i] /= tmp; + } + } + if (n == 2) { + x[0] = a[1]; + x[1] = a[2]; + return; + } + else if (n == 1) { + x[0] = a[1]; + return; + } + m = n; + b = new double [n+1]; + z = new double [n+1]; + b[0] = 1.0; + for (int i=0; i<=n; i++) { + z[i] = a[i]; + x[i] = 0.0; + } + do { + if (n > m) { + quad[0] = 3.14159e-1; + quad[1] = 2.78127e-1; + } + do { // This loop tries to assure convergence + //for (i=0;i<5;i++) { + find_quad(z,m,b,quad,&err,&iter); + + if ((err > 1e-7) || (iter > maxiter)) { + diff_poly(z,m,b); + recurse(z,m,b,m-1,quad,&err,&iter); + } + deflate(z,m,b,quad,&err); + if (err > minerr){ + quad[0] = ( (float)rand()/((float)RAND_MAX/10.0) ) - 5.0; + quad[1] = ( (float)rand()/((float)RAND_MAX/10.0) ) - 5.0; + } + /* + if (err < (minerr/2.0)) break; + // quad[0] = random(8) - 4.0; + quad[0] = ( (float)rand()/((float)RAND_MAX/8.0) ) - 4.0; + // quad[1] = random(8) - 4.0; + quad[1] = ( (float)rand()/((float)RAND_MAX/8.0) ) - 4.0; + // } + */ + /* if (err > 0.01) { + printf("Error! Convergence failure in quadratic x^2 + r*x + s."); + exit(1); + }*/ + } while (err > minerr); + x[m-2] = quad[1]; + x[m-1] = quad[0]; + m -= 2; + for (int i=0; i<=m; i++) { + z[i] = b[i]; + } + } while (m > 2); + if (m == 2) { + x[0] = b[1]; + x[1] = b[2]; + } + else x[0] = b[1]; + delete [] z; + delete [] b; +} + +/* +int main() +{ + double a[21],x[21],wr[21],wi[21],quad[2],err,t; + int n,iter,i,numr; + + cout << "Polynomial order (1 <= n <= 20): "; + cin >> n; + if ((n < 1) || (n > 20)) { + cout << "Error! Invalid order: n = " << n << endl; + return 1; + } +// get coefficients of polynomial + cout << "Enter coefficients, high order to low order" << endl; + for (i=0;i<=n;i++) { + cout << "C[" << n-i << "] * x^" << n-i << " : "; + cin >> a[i]; + if (a[0] == 0) { + cout << "Error! Highest coefficient cannot be 0." << endl; + return 0; + } + } + if (a[n] == 0) { + cout << "Error! Lowest coefficient (constant term) cannot be 0." << endl; + return 0; + } +// initialize estimate for 1st root pair + quad[0] = 2.71828e-1; + quad[1] = 3.14159e-1; +// cout << "Estimate for 'R': "; +// cin >> quad[1]; +// cout << "Estimate for 'S': "; +// cin >> quad[0]; +// get roots + get_quads(a,n,quad,x); + numr = roots(x,n,wr,wi); + + cout << endl << "Roots (" << numr << " found):" << endl; + cout.setf(ios::showpoint|ios::showpos|ios::left|ios::scientific); + cout.precision(15); + for (i=0;i<n;i++) { + if ((wr[i] != 0.0) || (wi[i] != 0.0)) + cout << wr[i] << " " << wi[i] << "I" << endl; + } + return 0; +} +*/ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/bbpr.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/bbpr.h new file mode 100644 index 0000000000000000000000000000000000000000..6f787ca195dc69d8f306457319b4814218756f0a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/bbpr.h @@ -0,0 +1,22 @@ +/** + * @file bbpr.h + * + * Finds all roots of polynomial by first finding quadratic + * factors using Bairstow's method, then extracting roots + * from quadratics. Implements new algorithm for managing + * multiple roots. + * + * @copyright + * Copyright (C) 2002, 2003, C. Bond. + * All rights reserved. + * + * @see http://www.crbond.com/ + */ + +#ifndef _bbpr_h_ +#define _bbpr_h_ + +int roots(double *a,int n,double *wr,double *wi); +void get_quads(double *a,int n,double *quad,double *x); + +#endif /* _bbpr_h_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/rpoly.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/rpoly.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f468dc874a1b4a217dc69bb2c2ed566c59d85dc9 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/rpoly.cpp @@ -0,0 +1,766 @@ +/** + * @file rpoly.cpp + * @brief Jenkins-Traub real polynomial root finder. + * + * @copyright + * Copyright (C) 2002, C. Bond. + * All rights reserved. + * + * @see http://www.crbond.com/ + * + * Translation of TOMS493 from FORTRAN to C. This + * implementation of Jenkins-Traub partially adapts + * the original code to a C environment by restruction + * many of the 'goto' controls to better fit a block + * structured form. It also eliminates the global memory + * allocation in favor of local, dynamic memory management. + * + * The calling conventions are slightly modified to return + * the number of roots found as the function value. + * + * INPUT: + * op - double precision vector of coefficients in order of + * decreasing powers. + * degree - integer degree of polynomial + * + * OUTPUT: + * zeror,zeroi - output double precision vectors of the + * real and imaginary parts of the zeros. + * + * RETURN: + * returnval: -1 if leading coefficient is zero, otherwise + * number of roots found. + */ + +#include <stdio.h> +#include <time.h> +#include <math.h> +#include <stdlib.h> + +void quad(double a,double b1,double c,double *sr,double *si, + double *lr,double *li); +void fxshfr(int l2, int *nz); +void quadit(double *uu,double *vv,int *nz); +void realit(double sss, int *nz, int *iflag); +void calcsc(int *type); +void nextk(int *type); +void newest(int type,double *uu,double *vv); +void quadsd(int n,double *u,double *v,double *p,double *q, + double *a,double *b); +double *p,*qp,*k,*qk,*svk; +double sr,si,u,v,a,b,c,d,a1,a2; +double a3,a6,a7,e,f,g,h,szr,szi,lzr,lzi; +double eta,are,mre; +int n,nn,nmi,zerok; +static int itercnt; + +int rpoly(double *op, int degree, double *zeror, double *zeroi, int info[] ) +{ + double t,aa,bb,cc,*temp,factor,rot; + double *pt; + double lo,max,min,xx,yy,cosr,sinr,xxx,x,sc,bnd; + double xm,ff,df,dx,infin,smalno,base; + int cnt,nz,i,j,jj,l,nm1,zerok; + long sec; + + sec = clock(); + +/* The following statements set machine constants. */ + base = 2.0; + eta = 2.22e-16; + infin = 3.4e38; + smalno = 1.2e-38; + + are = eta; + mre = eta; + lo = smalno/eta; +/* Initialization of constants for shift rotation. */ + xx = sqrt(0.5); + yy = -xx; + rot = 94.0; + rot *= 0.017453293; + cosr = cos(rot); + sinr = sin(rot); + n = degree; +/* Algorithm fails of the leading coefficient is zero. */ + if (op[0] == 0.0) return -1; +/* Remove the zeros at the origin, if any. */ + while (op[n] == 0.0) { + j = degree - n; + zeror[j] = 0.0; + zeroi[j] = 0.0; + n--; + } + if (n < 1) return degree; +/* + * Allocate memory here + */ + temp = new double [degree+1]; + pt = new double [degree+1]; + p = new double [degree+1]; + qp = new double [degree+1]; + k = new double [degree+1]; + qk = new double [degree+1]; + svk = new double [degree+1]; +/* Make a copy of the coefficients. */ + for (i=0;i<=n;i++) + p[i] = op[i]; +/* Start the algorithm for one zero. */ +_40: + itercnt = 0; + if (n == 1) { + zeror[degree-1] = -p[1]/p[0]; + zeroi[degree-1] = 0.0; + n -= 1; + if( info != NULL ) + info[ degree ] = 0; + + goto _99; + } +/* Calculate the final zero or pair of zeros. */ + if (n == 2) { + quad(p[0],p[1],p[2],&zeror[degree-2],&zeroi[degree-2], + &zeror[degree-1],&zeroi[degree-1]); + n -= 2; + if( info != NULL ) + info[ degree ] = info[ degree - 1] = 0; + goto _99; + } +/* Find largest and smallest moduli of coefficients. */ + max = 0.0; + min = infin; + for (i=0;i<=n;i++) { + x = fabs(p[i]); + if (x > max) max = x; + if (x != 0.0 && x < min) min = x; + } +/* Scale if there are large or very small coefficients. + * Computes a scale factor to multiply the coefficients of the + * polynomial. The scaling si done to avoid overflow and to + * avoid undetected underflow interfering with the convergence + * criterion. The factor is a power of the base. + */ + sc = lo/min; + if (sc > 1.0 && infin/sc < max) goto _110; + if (sc <= 1.0) { + if (max < 10.0) goto _110; + if (sc == 0.0) + sc = smalno; + } + l = (int)(log(sc)/log(base) + 0.5); + factor = pow(base*1.0,l); + if (factor != 1.0) { + for (i=0;i<=n;i++) + p[i] = factor*p[i]; /* Scale polynomial. */ + } +_110: +/* Compute lower bound on moduli of roots. */ + for (i=0;i<=n;i++) { + pt[i] = (fabs(p[i])); + } + pt[n] = - pt[n]; +/* Compute upper estimate of bound. */ + x = exp((log(-pt[n])-log(pt[0])) / (double)n); +/* If Newton step at the origin is better, use it. */ + if (pt[n-1] != 0.0) { + xm = -pt[n]/pt[n-1]; + if (xm < x) x = xm; + } +/* Chop the interval (0,x) until ff <= 0 */ + while (1) { + xm = x*0.1; + ff = pt[0]; + for (i=1;i<=n;i++) + ff = ff*xm + pt[i]; + if (ff <= 0.0) break; + x = xm; + } + dx = x; +/* Do Newton interation until x converges to two + * decimal places. + */ + while (fabs(dx/x) > 0.005) { + ff = pt[0]; + df = ff; + for (i=1;i<n;i++) { + ff = ff*x + pt[i]; + df = df*x + ff; + } + ff = ff*x + pt[n]; + dx = ff/df; + x -= dx; + itercnt++; + } + bnd = x; +/* Compute the derivative as the initial k polynomial + * and do 5 steps with no shift. + */ + nm1 = n - 1; + for (i=1;i<n;i++) + k[i] = (double)(n-i)*p[i]/(double)n; + k[0] = p[0]; + aa = p[n]; + bb = p[n-1]; + zerok = (k[n-1] == 0); + for(jj=0;jj<5;jj++) { + itercnt++; + cc = k[n-1]; + if (!zerok) { +/* Use a scaled form of recurrence if value of k at 0 is nonzero. */ + t = -aa/cc; + for (i=0;i<nm1;i++) { + j = n-i-1; + k[j] = t*k[j-1]+p[j]; + } + k[0] = p[0]; + zerok = (fabs(k[n-1]) <= fabs(bb)*eta*10.0); + } + else { +/* Use unscaled form of recurrence. */ + for (i=0;i<nm1;i++) { + j = n-i-1; + k[j] = k[j-1]; + } + k[0] = 0.0; + zerok = (k[n-1] == 0.0); + } + } +/* Save k for restarts with new shifts. */ + for (i=0;i<n;i++) + temp[i] = k[i]; +/* Loop to select the quadratic corresponding to each new shift. */ + for (cnt = 0;cnt < 20;cnt++) { +/* Quadratic corresponds to a double shift to a + * non-real point and its complex conjugate. The point + * has modulus bnd and amplitude rotated by 94 degrees + * from the previous shift. + */ + xxx = cosr*xx - sinr*yy; + yy = sinr*xx + cosr*yy; + xx = xxx; + sr = bnd*xx; + si = bnd*yy; + u = -2.0 * sr; + v = bnd; + fxshfr(20*(cnt+1),&nz); + if (nz != 0) { +/* The second stage jumps directly to one of the third + * stage iterations and returns here if successful. + * Deflate the polynomial, store the zero or zeros and + * return to the main algorithm. + */ + j = degree - n; + zeror[j] = szr; + zeroi[j] = szi; + if( info != NULL ) + info[ j + 1 ] = itercnt; + n -= nz; + for (i=0;i<=n;i++) + p[i] = qp[i]; + if (nz != 1) { + zeror[j+1] = lzr; + zeroi[j+1] = lzi; + if( info != NULL ) + info[ j + 2 ] = 0; + } + goto _40; + } +/* If the iteration is unsuccessful another quadratic + * is chosen after restoring k. + */ + for (i=0;i<n;i++) { + k[i] = temp[i]; + } + } +/* Return with failure if no convergence after 20 shifts. */ +_99: + delete [] svk; + delete [] qk; + delete [] k; + delete [] qp; + delete [] p; + delete [] pt; + delete [] temp; + + if( info != NULL ){ + info[ 0 ] = clock() - sec; + info[ 0 ] *= 1000; + info[ 0 ] /= CLOCKS_PER_SEC; + } + + return degree - n; +} +/* Computes up to L2 fixed shift k-polynomials, + * testing for convergence in the linear or quadratic + * case. Initiates one of the variable shift + * iterations and returns with the number of zeros + * found. + */ +void fxshfr(int l2,int *nz) +{ + double svu,svv,ui,vi,s; + double betas,betav,oss,ovv,ss,vv,ts,tv; + double ots,otv,tvv,tss; + int type, i,j,iflag,vpass,spass,vtry,stry; + + *nz = 0; + betav = 0.25; + betas = 0.25; + oss = sr; + ovv = v; +/* Evaluate polynomial by synthetic division. */ + quadsd(n,&u,&v,p,qp,&a,&b); + calcsc(&type); + for (j=0;j<l2;j++) { +/* Calculate next k polynomial and estimate v. */ + nextk(&type); + calcsc(&type); + newest(type,&ui,&vi); + vv = vi; +/* Estimate s. */ + ss = 0.0; + if (k[n-1] != 0.0) ss = -p[n]/k[n-1]; + tv = 1.0; + ts = 1.0; + if (j == 0 || type == 3) goto _70; +/* Compute relative measures of convergence of s and v sequences. */ + if (vv != 0.0) tv = fabs((vv-ovv)/vv); + if (ss != 0.0) ts = fabs((ss-oss)/ss); +/* If decreasing, multiply two most recent convergence measures. */ + tvv = 1.0; + if (tv < otv) tvv = tv*otv; + tss = 1.0; + if (ts < ots) tss = ts*ots; +/* Compare with convergence criteria. */ + vpass = (tvv < betav); + spass = (tss < betas); + if (!(spass || vpass)) goto _70; +/* At least one sequence has passed the convergence test. + * Store variables before iterating. + */ + svu = u; + svv = v; + for (i=0;i<n;i++) { + svk[i] = k[i]; + } + s = ss; +/* Choose iteration according to the fastest converging + * sequence. + */ + vtry = 0; + stry = 0; + if ((spass && (!vpass)) || tss < tvv) goto _40; +_20: + quadit(&ui,&vi,nz); + if (*nz > 0) return; +/* Quadratic iteration has failed. Flag that it has + * been tried and decrease the convergence criterion. + */ + vtry = 1; + betav *= 0.25; +/* Try linear iteration if it has not been tried and + * the S sequence is converging. + */ + if (stry || !spass) goto _50; + for (i=0;i<n;i++) { + k[i] = svk[i]; + } +_40: + realit(s,nz,&iflag); + if (*nz > 0) return; +/* Linear iteration has failed. Flag that it has been + * tried and decrease the convergence criterion. + */ + stry = 1; + betas *=0.25; + if (iflag == 0) goto _50; +/* If linear iteration signals an almost double real + * zero attempt quadratic iteration. + */ + ui = -(s+s); + vi = s*s; + goto _20; +/* Restore variables. */ +_50: + u = svu; + v = svv; + for (i=0;i<n;i++) { + k[i] = svk[i]; + } +/* Try quadratic iteration if it has not been tried + * and the V sequence is convergin. + */ + if (vpass && !vtry) goto _20; +/* Recompute QP and scalar values to continue the + * second stage. + */ + quadsd(n,&u,&v,p,qp,&a,&b); + calcsc(&type); +_70: + ovv = vv; + oss = ss; + otv = tv; + ots = ts; + } +} +/* Variable-shift k-polynomial iteration for a + * quadratic factor converges only if the zeros are + * equimodular or nearly so. + * uu, vv - coefficients of starting quadratic. + * nz - number of zeros found. + */ +void quadit(double *uu,double *vv,int *nz) +{ + double ui,vi; + double mp,omp,ee,relstp,t,zm; + int type,i,j,tried; + + *nz = 0; + tried = 0; + u = *uu; + v = *vv; + j = 0; +/* Main loop. */ +_10: + itercnt++; + quad(1.0,u,v,&szr,&szi,&lzr,&lzi); +/* Return if roots of the quadratic are real and not + * close to multiple or nearly equal and of opposite + * sign. + */ + if (fabs(fabs(szr)-fabs(lzr)) > 0.01 * fabs(lzr)) return; +/* Evaluate polynomial by quadratic synthetic division. */ + quadsd(n,&u,&v,p,qp,&a,&b); + mp = fabs(a-szr*b) + fabs(szi*b); +/* Compute a rigorous bound on the rounding error in + * evaluating p. + */ + zm = sqrt(fabs(v)); + ee = 2.0*fabs(qp[0]); + t = -szr*b; + for (i=1;i<n;i++) { + ee = ee*zm + fabs(qp[i]); + } + ee = ee*zm + fabs(a+t); + ee *= (5.0 *mre + 4.0*are); + ee = ee - (5.0*mre+2.0*are)*(fabs(a+t)+fabs(b)*zm); + ee = ee + 2.0*are*fabs(t); +/* Iteration has converged sufficiently if the + * polynomial value is less than 20 times this bound. + */ + if (mp <= 20.0*ee) { + *nz = 2; + return; + } + j++; +/* Stop iteration after 20 steps. */ + if (j > 20) return; + if (j < 2) goto _50; + if (relstp > 0.01 || mp < omp || tried) goto _50; +/* A cluster appears to be stalling the convergence. + * Five fixed shift steps are taken with a u,v close + * to the cluster. + */ + if (relstp < eta) relstp = eta; + relstp = sqrt(relstp); + u = u - u*relstp; + v = v + v*relstp; + quadsd(n,&u,&v,p,qp,&a,&b); + for (i=0;i<5;i++) { + calcsc(&type); + nextk(&type); + } + tried = 1; + j = 0; +_50: + omp = mp; +/* Calculate next k polynomial and new u and v. */ + calcsc(&type); + nextk(&type); + calcsc(&type); + newest(type,&ui,&vi); +/* If vi is zero the iteration is not converging. */ + if (vi == 0.0) return; + relstp = fabs((vi-v)/vi); + u = ui; + v = vi; + goto _10; +} +/* Variable-shift H polynomial iteration for a real zero. + * sss - starting iterate + * nz - number of zeros found + * iflag - flag to indicate a pair of zeros near real axis. + */ +void realit(double sss, int *nz, int *iflag) +{ + double pv,kv,t,s; + double ms,mp,omp,ee; + int i,j; + + *nz = 0; + s = sss; + *iflag = 0; + j = 0; +/* Main loop */ + while (1) { + itercnt++; + pv = p[0]; +/* Evaluate p at s. */ + qp[0] = pv; + for (i=1;i<=n;i++) { + pv = pv*s + p[i]; + qp[i] = pv; + } + mp = fabs(pv); +/* Compute a rigorous bound on the error in evaluating p. */ + ms = fabs(s); + ee = (mre/(are+mre))*fabs(qp[0]); + for (i=1;i<=n;i++) { + ee = ee*ms + fabs(qp[i]); + } +/* Iteration has converged sufficiently if the polynomial + * value is less than 20 times this bound. + */ + if (mp <= 20.0*((are+mre)*ee-mre*mp)) { + *nz = 1; + szr = s; + szi = 0.0; return ; // HVE return added + } + j++; +/* Stop iteration after 10 steps. */ + if (j > 10) return; + if (j < 2) goto _50; + if (fabs(t) > 0.001*fabs(s-t) || mp < omp) goto _50; +/* A cluster of zeros near the real axis has been + * encountered. Return with iflag set to initiate a + * quadratic iteration. + */ + *iflag = 1; sss =s; // HVE sss=s added + return; +/* Return if the polynomial value has increased significantly. */ +_50: + omp = mp; +/* Compute t, the next polynomial, and the new iterate. */ + kv = k[0]; + qk[0] = kv; + for (i=1;i<n;i++) { + kv = kv*s + k[i]; + qk[i] = kv; + } + if (fabs(kv) <= fabs(k[n-1])*10.0*eta) { // HVE n -> n-1 +/* Use unscaled form. */ + k[0] = 0.0; + for (i=1;i<n;i++) { + k[i] = qk[i-1]; + } + } + else { +/* Use the scaled form of the recurrence if the value + * of k at s is nonzero. + */ + t = -pv/kv; + k[0] = qp[0]; + for (i=1;i<n;i++) { + k[i] = t*qk[i-1] + qp[i]; + } + } + kv = k[0]; + for (i=1;i<n;i++) { + kv = kv*s + k[i]; + } + t = 0.0; + if (fabs(kv) > fabs(k[n-1]*10.0*eta)) t = -pv/kv; + s += t; + } +} + +/* This routine calculates scalar quantities used to + * compute the next k polynomial and new estimates of + * the quadratic coefficients. + * type - integer variable set here indicating how the + * calculations are normalized to avoid overflow. + */ +void calcsc(int *type) +{ +/* Synthetic division of k by the quadratic 1,u,v */ + quadsd(n-1,&u,&v,k,qk,&c,&d); + if (fabs(c) > fabs(k[n-1]*100.0*eta)) goto _10; + if (fabs(d) > fabs(k[n-2]*100.0*eta)) goto _10; + *type = 3; +/* Type=3 indicates the quadratic is almost a factor of k. */ + return; +_10: + if (fabs(d) < fabs(c)) { + *type = 1; +/* Type=1 indicates that all formulas are divided by c. */ + e = a/c; + f = d/c; + g = u*e; + h = v*b; + a3 = a*e + (h/c+g)*b; + a1 = b - a*(d/c); + a7 = a + g*d + h*f; + return; + } + *type = 2; +/* Type=2 indicates that all formulas are divided by d. */ + e = a/d; + f = c/d; + g = u*b; + h = v*b; + a3 = (a+g)*e + h*(b/d); + a1 = b*f-a; + a7 = (f+u)*a + h; +} +/* Computes the next k polynomials using scalars + * computed in calcsc. + */ +void nextk(int *type) +{ + double temp; + int i; + + if (*type == 3) { +/* Use unscaled form of the recurrence if type is 3. */ + k[0] = 0.0; + k[1] = 0.0; + for (i=2;i<n;i++) { + k[i] = qk[i-2]; + } + return; + } + temp = a; + if (*type == 1) temp = b; + if (fabs(a1) <= fabs(temp)*eta*10.0) { +/* If a1 is nearly zero then use a special form of the + * recurrence. + */ + k[0] = 0.0; + k[1] = -a7*qp[0]; + for(i=2;i<n;i++) { + k[i] = a3*qk[i-2] - a7*qp[i-1]; + } return; // HVE return added + } +/* Use scaled form of the recurrence. */ + a7 /= a1; + a3 /= a1; + k[0] = qp[0]; + k[1] = qp[1] - a7*qp[0]; + for (i=2;i<n;i++) { + k[i] = a3*qk[i-2] - a7*qp[i-1] + qp[i]; + } +} +/* Compute new estimates of the quadratic coefficients + * using the scalars computed in calcsc. + */ +void newest(int type,double *uu,double *vv) +{ + double a4,a5,b1,b2,c1,c2,c3,c4,temp; + +/* Use formulas appropriate to setting of type. */ + if (type == 3) { +/* If type=3 the quadratic is zeroed. */ + *uu = 0.0; + *vv = 0.0; + return; + } + if (type == 2) { + a4 = (a+g)*f + h; + a5 = (f+u)*c + v*d; + } + else { + a4 = a + u*b +h*f; + a5 = c + (u+v*f)*d; + } +/* Evaluate new quadratic coefficients. */ + b1 = -k[n-1]/p[n]; + b2 = -(k[n-2]+b1*p[n-1])/p[n]; + c1 = v*b2*a1; + c2 = b1*a7; + c3 = b1*b1*a3; + c4 = c1 - c2 - c3; + temp = a5 + b1*a4 - c4; + if (temp == 0.0) { + *uu = 0.0; + *vv = 0.0; + return; + } + *uu = u - (u*(c3+c2)+v*(b1*a1+b2*a7))/temp; + *vv = v*(1.0+c4/temp); + return; +} + +/* Divides p by the quadratic 1,u,v placing the quotient + * in q and the remainder in a,b. + */ +void quadsd(int nn,double *u,double *v,double *p,double *q, + double *a,double *b) +{ + double c; + int i; + + *b = p[0]; + q[0] = *b; + *a = p[1] - (*b)*(*u); + q[1] = *a; + for (i=2;i<=nn;i++) { + c = p[i] - (*a)*(*u) - (*b)*(*v); + q[i] = c; + *b = *a; + *a = c; + } +} +/* Calculate the zeros of the quadratic a*z^2 + b1*z + c. + * The quadratic formula, modified to avoid overflow, is used + * to find the larger zero if the zeros are real and both + * are complex. The smaller real zero is found directly from + * the product of the zeros c/a. + */ +void quad(double a,double b1,double c,double *sr,double *si, + double *lr,double *li) +{ + double b,d,e; + + if (a == 0.0) { /* less than two roots */ + if (b1 != 0.0) *sr = -c/b1; + else *sr = 0.0; + *lr = 0.0; + *si = 0.0; + *li = 0.0; + return; + } + if (c == 0.0) { /* one real root, one zero root */ + *sr = 0.0; + *lr = -b1/a; + *si = 0.0; + *li = 0.0; + return; + } +/* Compute discriminant avoiding overflow. */ + b = b1/2.0; + if (fabs(b) < fabs(c)) { + if (c < 0.0) e = -a; + else e = a; + e = b*(b/fabs(c)) - e; + d = sqrt(fabs(e))*sqrt(fabs(c)); + } + else { + e = 1.0 - (a/b)*(c/b); + d = sqrt(fabs(e))*fabs(b); + } + if (e < 0.0) { /* complex conjugate zeros */ + *sr = -b/a; + *lr = *sr; + *si = fabs(d/a); + *li = -(*si); + } + else { + if (b >= 0.0) d = -d; /* real zeros. */ + *lr = (-b+d)/a; + *sr = 0.0; + if (*lr != 0.0) *sr = (c/ *lr)/a; + *si = 0.0; + *li = 0.0; + } +} + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/rpoly.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/rpoly.h new file mode 100644 index 0000000000000000000000000000000000000000..34e64070e1cacfe1eedfebad90be48a5b3128421 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/lpcformants/rpoly.h @@ -0,0 +1,40 @@ +/** + * @file rpoly.h + * @brief Jenkins-Traub real polynomial root finder. + * + * @copyright + * Copyright (C) 2002, C. Bond. + * All rights reserved. + * + * @see http://www.crbond.com/ + * + * Translation of TOMS493 from FORTRAN to C. This + * implementation of Jenkins-Traub partially adapts + * the original code to a C environment by restruction + * many of the 'goto' controls to better fit a block + * structured form. It also eliminates the global memory + * allocation in favor of local, dynamic memory management. + * + * The calling conventions are slightly modified to return + * the number of roots found as the function value. + * + * INPUT: + * op - double precision vector of coefficients in order of + * decreasing powers. + * degree - integer degree of polynomial + * + * OUTPUT: + * zeror,zeroi - output double precision vectors of the + * real and imaginary parts of the zeros. + * + * RETURN: + * returnval: -1 if leading coefficient is zero, otherwise + * number of roots found. + */ + +#ifndef _rpoly_h_ +#define _rpoly_h_ + +int rpoly(double *op, int degree, double *zeror, double *zeroi, int info[]); + +#endif /* _rpoly_h_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta.h new file mode 100644 index 0000000000000000000000000000000000000000..43d9e9980420f5df5b3b4bb3356bc308e0b7cebd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta.h @@ -0,0 +1,47 @@ +/** + * @file rta.h + * @author Jean-Philippe Lambert + * @date Mon Sep 10 11:05:09 2007 + * + * @brief Base header file for rta library. + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_H_ +#define _RTA_H_ 1 + +/** rta_configuration.h must be user-defined. */ +#include "rta_configuration.h" + +#include "rta_types.h" + +#endif /* _RTA_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_bpf.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_bpf.c new file mode 100644 index 0000000000000000000000000000000000000000..6d4e9aae864e1891fd80ee29d1007849132947e5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_bpf.c @@ -0,0 +1,94 @@ +/** + * @file rta_bpf.c + * @author Norbert.Schnell@ircam.fr + * + * @brief Break-point function utilities. + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_bpf.h" +#include "rta_float.h" // for DBL_MAX + +static int rta_bf_get_index (rta_bpf_t *bpf, double time) +{ + int size = rta_bpf_get_size(bpf); + int index = bpf->index; + + if (index >= size - 1) + index = size - 2; + + /* search index */ + if (time >= rta_bpf_get_time(bpf, index + 1)) + { + index++; + + while (time >= rta_bpf_get_time(bpf, index + 1)) + index++; + } + else if (time < rta_bpf_get_time(bpf, index)) + { + index--; + + while (time < rta_bpf_get_time(bpf, index)) + index--; + } + else if (rta_bpf_get_slope(bpf, index) == DBL_MAX) + { + index++; + + while (rta_bpf_get_slope(bpf, index) == DBL_MAX) + index++; + } + + bpf->index = index; + + return index; +} + + +double rta_bpf_get_interpolated (rta_bpf_t *self, double time) +{ + double duration = rta_bpf_get_duration(self); + + if (time <= rta_bpf_get_time(self, 0)) + return rta_bpf_get_value(self, 0); + else if (time >= duration) + { + int size = rta_bpf_get_size(self); + return rta_bpf_get_value(self, size - 1); + } + else + { + int index = rta_bf_get_index(self, time); + return rta_bpf_get_value(self, index) + (time - rta_bpf_get_time(self, index)) * rta_bpf_get_slope(self, index); + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_bpf.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_bpf.h new file mode 100644 index 0000000000000000000000000000000000000000..19fa0033c18fd6b594107b0e49f083a23379c36f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_bpf.h @@ -0,0 +1,86 @@ +/** + * @file rta_bpf.h + * @author Norbert Schnell + * + * @brief Break-point function utilities. + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_BPF_H_ +#define _RTA_BPF_H_ + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Break-point function (or time-tagged values). + * + * For the moment read only, since construction is done by binary-compatible bpf_t from FTM + */ + +/* a single bpf point */ +typedef struct rta_bpf_point +{ + double time; /**< absolute break point time */ + double value; /**< break point value */ + double slope; /**< slope to next value */ +} rta_bpf_point_t; + +/** the break-point function itself + * + * ATTENTION: must be binary-compatible with FTM struct bpfunc in ftmlib/classes/bpf.c!!! + */ +typedef struct _rta_bpf +{ + rta_bpf_point_t *points; /**< break points ... */ + int alloc; /**< alloc ... */ + int size; /**< size ... */ + int index; /**< index cache for get_interpolated method */ +} rta_bpf_t; + + +#define rta_bpf_get_size(b) ((b)->size) +#define rta_bpf_get_time(b, i) ((b)->points[i].time) +#define rta_bpf_get_value(b, i) ((b)->points[i].value) +#define rta_bpf_get_slope(b, i) ((b)->points[i].slope) +#define rta_bpf_get_duration(b) ((b)->points[(b)->size - 1].time) + +double rta_bpf_get_interpolated (rta_bpf_t *bpf, double time); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_BPF_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_complex.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_complex.h new file mode 100644 index 0000000000000000000000000000000000000000..ca2a5b8e002eb69472af8d148b012bd65015d2b7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_complex.h @@ -0,0 +1,299 @@ +/** + * @file rta_complex.h + * @author Jean-Philippe Lambert + * @date Mon Sep 10 11:05:09 2007 + * + * @brief rta_complex_t type warper for float, double or long double + * complex. + * + * Default is the same as RTA_REAL_TYPE. Define your RTA_COMPLEX_TYPE to + * override these. + * @see rta_configuration.h + * @see rta_real.h + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_COMPLEX_H_ +#define _RTA_COMPLEX_H_ 1 + +#include "rta.h" + +/** default complex precision is the same as real precision */ +#ifndef RTA_COMPLEX_TYPE +#define RTA_COMPLEX_TYPE RTA_REAL_TYPE +#endif + +#ifdef WIN32 + +#if (RTA_COMPLEX_TYPE == RTA_FLOAT_TYPE) +#undef rta_complex_t + +typedef struct floatcomplex_ +{ + float real; + float imag; +} floatcomplex; + +#define rta_complex_t floatcomplex +#define inline + +static inline rta_complex_t rta_make_complex(float real, float imag) +{ + rta_complex_t z = {real, imag}; + return z; +} +#endif + +#if (RTA_COMPLEX_TYPE == RTA_DOUBLE_TYPE) +#undef rta_complex_t + +typedef struct complex_ +{ + double real; + double imag; +} complex; + +#define rta_complex_t complex +static inline rta_complex_t rta_make_complex(double real, double imag) +{ + rta_complex_t z = {real, imag}; + return z; +} +#endif + +#if (RTA_COMPLEX_TYPE == RTA_LONG_DOUBLE_TYPE) +#undef rta_complex_t + +typedef struct complex_ +{ + long double real; + long double imag; +} complex; + +#define rta_complex_t complex +static inline rta_complex_t rta_make_complex(long double real, long double imag) +{ + rta_complex_t z = {real, imag}; + return z; +} +#endif + +#define creal(z) ((z).real) +#define cimag(z) ((z).imag) + +static inline rta_complex_t rta_add_complex(rta_complex_t a, rta_complex_t b) +{ + rta_complex_t z = {a.real + b.real, a.imag + b.imag}; + return z; +} + +static inline rta_complex_t rta_sub_complex(rta_complex_t a, rta_complex_t b) +{ + rta_complex_t z = {a.real - b.real, a.imag - b.imag}; + return z; +} + +static inline rta_complex_t rta_mul_complex(rta_complex_t a, rta_complex_t b) +{ + rta_complex_t z = {a.real * b.real - a.imag * b.imag, a.imag * b.real + a.real * b.imag}; + return z; +} + +static inline rta_complex_t rta_mul_complex_real(rta_complex_t a, float b) +{ + rta_complex_t z = {a.real * b, a.imag * b}; + return z; +} + +static inline rta_complex_t rta_div_complex(rta_complex_t a, rta_complex_t b) +{ + rta_complex_t z = {(a.real * b.real + a.imag * b.imag)/(b.real * b.real + b.imag * b.imag), (b.real * a.imag - a.real * b.imag) / (b.real * b.real + b.imag * b.imag)}; + return z; +} + +static inline rta_complex_t rta_conj(rta_complex_t a) +{ + rta_complex_t z = {a.real, -a.imag}; + return z; +} + +static inline void rta_set_complex_real(rta_complex_t a, float b) +{ + a.real = b; + a.imag = 0.0; +} + +#define rta_cabs cabs +#define rta_cacos cacos +#define rta_cacosh cacosh +#define rta_carg carg +#define rta_casin casin +#define rta_casinh casinh +#define rta_catan catan +#define rta_catanh catanh +#define rta_ccos ccos +#define rta_ccosh ccosh +#define rta_cexp cexp +#define rta_cimag cimag +#define rta_clog clog +#define rta_cpow cpow +#define rta_cproj cproj +#define rta_creal creal +#define rta_csin csin +#define rta_csinh csinh +#define rta_csqrt csqrt +#define rta_ctan ctan +#define rta_ctanh ctanh + +#else + +#ifndef __cplusplus +#include <complex.h> +#else +#include "/usr/include/complex.h" +#endif + +#if (RTA_COMPLEX_TYPE == RTA_FLOAT_TYPE) +#undef rta_complex_t +#define rta_complex_t float complex + +static inline rta_complex_t rta_make_complex(float real, float imag) +{ +#if (__STDC_VERSION__ > 199901L || __DARWIN_C_LEVEL >= __DARWIN_C_FULL) \ + && defined __clang__ + return CMPLX(real, imag); +#else // old gcc way of creating a complex number + return (real + imag * I); +#endif +} + +#define rta_cabs cabsf +#define rta_cacos cacosf +#define rta_cacosh cacoshf +#define rta_carg cargf +#define rta_casin casinf +#define rta_casinh casinhf +#define rta_catan catanf +#define rta_catanh catanhf +#define rta_ccos ccosf +#define rta_ccosh ccoshf +#define rta_cexp cexpf +#define rta_cimag cimagf +#define rta_clog clogf +#define rta_conj conjf +#define rta_cpow cpowf +#define rta_cproj cprojf +#define rta_creal crealf +#define rta_csin csinf +#define rta_csinh csinhf +#define rta_csqrt csqrtf +#define rta_ctan ctanf +#define rta_ctanh ctanhf + +#endif + +#if (RTA_COMPLEX_TYPE == RTA_DOUBLE_TYPE) +#undef rta_complex_t +#define rta_complex_t double complex +static inline rta_complex_t rta_make_complex(double real, double imag) +{ + return real + imag * I; +} + +#define rta_cabs cabs +#define rta_cacos cacos +#define rta_cacosh cacosh +#define rta_carg carg +#define rta_casin casin +#define rta_casinh casinh +#define rta_catan catan +#define rta_catanh catanh +#define rta_ccos ccos +#define rta_ccosh ccosh +#define rta_cexp cexp +#define rta_cimag cimag +#define rta_clog clog +#define rta_conj conj +#define rta_cpow cpow +#define rta_cproj cproj +#define rta_creal creal +#define rta_csin csin +#define rta_csinh csinh +#define rta_csqrt csqrt +#define rta_ctan ctan +#define rta_ctanh ctanh + +#endif + +#if (RTA_COMPLEX_TYPE == RTA_LONG_DOUBLE_TYPE) +#undef rta_complex_t +#define rta_complex_t long double complex +static inline rta_complex_t rta_make_complex(long double real, long double imag) +{ + return real + imag * I; +} + +#define rta_cabs cabsl +#define rta_cacos cacosl +#define rta_cacosh cacoshl +#define rta_carg cargl +#define rta_casin casinl +#define rta_casinh casinhl +#define rta_catan catanl +#define rta_catanh catanhl +#define rta_ccos ccosl +#define rta_ccosh ccoshl +#define rta_cexp cexpl +#define rta_cimag cimagl +#define rta_clog clogl +#define rta_conj conjl +#define rta_cpow cpowl +#define rta_cproj cprojl +#define rta_creal creall +#define rta_csin csinl +#define rta_csinh csinhl +#define rta_csqrt csqrtl +#define rta_ctan ctanl +#define rta_ctanh ctanhl + +#endif + +#define rta_add_complex(a, b) ((a)+(b)) +#define rta_sub_complex(a, b) ((a)-(b)) +#define rta_mul_complex(a, b) ((a)*(b)) +#define rta_div_complex(a, b) ((a)/(b)) +#define rta_mul_complex_real(a, b) ((a)*(b)) +#define rta_set_complex_real(a, b) ((a) = (b)) + +#endif /* WIN32 */ + +#endif /* _RTA_COMPLEX_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_float.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_float.h new file mode 100644 index 0000000000000000000000000000000000000000..c9d996f7e297945f579605c0af0d81471cf3464b --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_float.h @@ -0,0 +1,95 @@ +/** + * @file rta_float.h + * @author Jean-Philippe Lambert + * @date Mon Sep 10 11:05:09 2007 + * + * @brief rta_real_t type wrapper for <float.h> + * + * Default is RTA_REAL_FLOAT. Define your RTA_REAL_TYPE (into + * rta_configuration.h) to override these. + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_FLOAT_H_ +#define _RTA_FLOAT_H_ 1 + +#include "rta.h" + +/** @name Real type constants */ +/** @{ */ +#if (RTA_REAL_TYPE == RTA_FLOAT_TYPE) + +#define RTA_REAL_DIG FLT_DIG +#define RTA_REAL_EPSILON FLT_EPSILON +#define RTA_REAL_MANT_DIG FLT_MANT_DIG +#define RTA_REAL_MAX FLT_MAX +#define RTA_REAL_MAX_10_EXP FLT_MAX_10_EXP +#define RTA_REAL_MAX_EXP FLT_MAX_EXP +#define RTA_REAL_MIN FLT_MIN +#define RTA_REAL_MIN_10_EXP FLT_MIN_10_EXP +#define RTA_REAL_MIN_EXP FLT_MIN_EXP + +#endif /* float */ + +#if (RTA_REAL_TYPE == RTA_DOUBLE_TYPE) + +#define RTA_REAL_DIG DBL_DIG +#define RTA_REAL_EPSILON DBL_EPSILON +#define RTA_REAL_MANT_DIG DBL_MANT_DIG +#define RTA_REAL_MAX DBL_MAX +#define RTA_REAL_MAX_10_EXP DBL_MAX_10_EXP +#define RTA_REAL_MAX_EXP DBL_MAX_EXP +#define RTA_REAL_MIN DBL_MIN +#define RTA_REAL_MIN_10_EXP DBL_MIN_10_EXP +#define RTA_REAL_MIN_EXP DBL_MIN_EXP + +#endif /* double */ + +#if (RTA_REAL_TYPE == RTA_LONG_DOUBLE_TYPE) + +#define RTA_REAL_DIG LDBL_DIG +#define RTA_REAL_EPSILON LDBL_EPSILON +#define RTA_REAL_MANT_DIG LDBL_MANT_DIG +#define RTA_REAL_MAX LDBL_MAX +#define RTA_REAL_MAX_10_EXP LDBL_MAX_10_EXP +#define RTA_REAL_MAX_EXP LDBL_MAX_EXP +#define RTA_REAL_MIN LDBL_MIN +#define RTA_REAL_MIN_10_EXP LDBL_MIN_10_EXP +#define RTA_REAL_MIN_EXP LDBL_MIN_EXP + +#endif /* long double */ +/** @} */ +/* Real type constants */ + +#include <float.h> + +#endif /* _RTA_FLOAT_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_int.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_int.c new file mode 100644 index 0000000000000000000000000000000000000000..3a033a311cc2e9013bfbe21a7ce31ae23f5b8678 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_int.c @@ -0,0 +1,80 @@ +/** + * @file rta_int.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Thu Sep 12 18:10:41 2007 + * + * @brief Integer mathematical functions + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_int.h" + + +unsigned int +rta_ilog2(unsigned int n) +{ + unsigned int log2 = 0; + int i; + + for(i=n>>1; i; i>>=1) + { + log2++; + } + + return log2; +} + +inline int rta_imax(int m, int n) +{ + return (m > n) ? m : n; +} + +inline int rta_imin(int m, int n) +{ + return (m < n) ? m : n; +} + +unsigned int +rta_inextpow2(unsigned int n) +{ + unsigned int pow2 = 2; + int i; + + for(i=((n-1)>>1); i>0; i>>=1) + { + pow2 <<= 1; + } + + return pow2; +} + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_int.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_int.h new file mode 100644 index 0000000000000000000000000000000000000000..07e0ae8334bbcf0b352c5fdec15a788c4785d62a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_int.h @@ -0,0 +1,94 @@ +/** + * @file rta_int.h + * @author Jean-Philippe Lambert + * @date Thu Sep 12 18:10:41 2007 + * + * @brief Integer mathematical functions + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_INT_H_ +#define _RTA_INT_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#define inline +#endif +/** + * Integer version of the log2 function (rounded down) + * + * @param n + * + * @return log2('n') or 0 if 'n' == 0 + */ +unsigned int rta_ilog2(unsigned int n); + +/** + * Integer version of the maximum + * + * @param m + * @param n + * + * @return the smallest integer between 'm' and 'n' + */ +extern inline int rta_imax(int m, int n); + +/** + * Integer version of the minimum + * + * @param m + * @param n + * + * @return the smallest integer between 'm' and 'n' + */ +extern inline int rta_imin(int m, int n); + + +/** + * Next (or equal) 'n' power of 2 + * + * @param n + * + * @return minimum p such as 2^p >= 'n' + */ +unsigned int rta_inextpow2(unsigned int n); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_INT_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_math.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_math.h new file mode 100644 index 0000000000000000000000000000000000000000..6d2d36fed7948bdfe754803c21e8745a30a24ba4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_math.h @@ -0,0 +1,250 @@ +/** + * @file rta_math.h + * @author Jean-Philippe Lambert + * @date Mon Sep 10 11:05:09 2007 + * + * @brief Mathematical functions, <math.h> for rta_real_t type + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_MATH_H_ +#define _RTA_MATH_H_ 1 + +#include "rta.h" + + +#ifdef WIN32 +/* TODO: check every windows functions against C99 */ +/* float and double functions differenciation */ + +#define rta_max(a,b) (((a)>(b))? (a) : (b)) +#define rta_min(a,b) (((a)<(b))? (a) : (b)) + +#define rta_abs fabs +#define rta_floor floor +#define rta_ceil ceil + +/* round is C99 but does not seem to exist on windows (visual studio 6) */ +#define rta_round(a)(floor((a) + 0.5)) +#define rta_lround(a)(floor((a) + 0.5)) +#define rta_llround(a)(floor((a) + 0.5)) + +#define rta_sqrt sqrt +#define rta_pow pow + +#define rta_log log +#define rta_log2 log2 +#define rta_log10 log10 +#define rta_log1p log1p + +#define rta_exp exp +#define rta_exp2 exp2 +#define rta_expm1 expm1 + +#define rta_cos cos +#define rta_sin sin + +#define rta_hypot hypot + +#else + +#if (RTA_REAL_TYPE == RTA_FLOAT_TYPE) + +#define rta_max fmaxf +#define rta_min fminf + +#define rta_abs fabsf +#define rta_floor floorf +#define rta_ceil ceilf +#define rta_round roundf +#define rta_lround lroundf +#define rta_llround llroundf + +#define rta_sqrt sqrtf +#define rta_pow powf + +#define rta_log logf +#define rta_log2 log2f +#define rta_log10 log10f +#define rta_log1p log1pf + +#define rta_exp expf +#define rta_exp2 exp2f +#define rta_expm1 expm1f + +#define rta_cos cosf +#define rta_sin sinf + +#define rta_hypot hypotf + +#endif + +#if (RTA_REAL_TYPE == RTA_DOUBLE_TYPE) + +#define rta_max fmax +#define rta_min fmin + +#define rta_abs fabs +#define rta_floor floor +#define rta_ceil ceil +#define rta_round round +#define rta_lround lround +#define rta_llround llround + +#define rta_sqrt sqrt +#define rta_pow pow + +#define rta_log log +#define rta_log2 log2 +#define rta_log10 log10 +#define rta_log1p log1p + +#define rta_exp exp +#define rta_exp2 exp2 +#define rta_expm1 expm1 + +#define rta_cos cos +#define rta_sin sin + +#define rta_hypot hypot + +#endif + +#if (RTA_REAL_TYPE == RTA_LONG_DOUBLE_TYPE) + +#define rta_max fmaxl +#define rta_min fminl + +#define rta_abs fabsl +#define rta_floor floorl +#define rta_ceil ceill +#define rta_round roundl +#define rta_lround lroundl +#define rta_llround llroundl + +#define rta_sqrt sqrtl +#define rta_pow powl + +#define rta_log logl +#define rta_log2 log2l +#define rta_log10 log10l +#define rta_log1p log1pl + +#define rta_exp expl +#define rta_exp2 exp2l +#define rta_expm1 expm1l + +#define rta_cos cosl +#define rta_sin sinl + +#define rta_hypot hypotl + +#endif + +#endif /* WIN32 */ + +#include <math.h> + +/** @name Numerical constants */ +/** @{ */ +#ifndef M_E +#define M_E 2.71828182845904523536028747135 /**< e */ +#endif + +#ifndef M_LOG2E +#define M_LOG2E 1.44269504088896340735992468100 /**< log_2 (e) */ +#endif + +#ifndef M_LOG10E +#define M_LOG10E 0.43429448190325182765112891892 /**< log_10 (e) */ +#endif + +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880168872421 /**< sqrt(2) */ +#endif + +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440084436210 /**< sqrt(1/2) */ +#endif + + +#ifndef M_SQRT3 +#define M_SQRT3 1.73205080756887729352744634151 /**< sqrt(3) */ +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338328 /**< pi */ +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923132169164 /**< pi/2 */ +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830961566084582 /**< pi/4 */ +#endif + +#ifndef M_SQRTPI +#define M_SQRTPI 1.77245385090551602729816748334 /**< sqrt(pi) */ +#endif + +#ifndef M_2_SQRTPI +#define M_2_SQRTPI 1.12837916709551257389615890312 /**< 2/sqrt(pi) */ +#endif + +#ifndef M_1_PI +#define M_1_PI 0.31830988618379067153776752675 /**< 1/pi */ +#endif + +#ifndef M_2_PI +#define M_2_PI 0.63661977236758134307553505349 /**< 2/pi */ +#endif + +#ifndef M_LN10 +#define M_LN10 2.30258509299404568401799145468 /**< ln(10) */ +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530941723212146 /**< ln(2) */ +#endif + +#ifndef M_LNPI +#define M_LNPI 1.14472988584940017414342735135 /**< ln(pi) */ +#endif + +#ifndef M_EULER +#define M_EULER 0.57721566490153286060651209008 /**< Euler constant */ +#endif +/*@} */ +/* Numerical constants */ + +#endif /* _RTA_MATH_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_stdio.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_stdio.h new file mode 100644 index 0000000000000000000000000000000000000000..646d60e2f1da3ccf6aa3470dec86d36305b488d2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_stdio.h @@ -0,0 +1,51 @@ +/** + * @file rta_stdio.h + * @author Diemo Schwarz + * @date 30.10.2008 + * + * @brief Default defines for the rta library + * + * Define your own to override these. + * @see rta_configuration.h + * + * @copyright + * Copyright (C) 2008 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_STDIO_H_ +#define _RTA_STDIO_H_ 1 + +/** default define for console printing */ +#ifndef rta_post +#define rta_post printf +#include <stdio.h> +#endif + +#endif /* _RTA_STDIO_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_stdlib.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_stdlib.h new file mode 100644 index 0000000000000000000000000000000000000000..c1051dc9bd1b9846088d2e8fe98d1f941c1ac9d3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_stdlib.h @@ -0,0 +1,74 @@ +/** + * @file rta_stdlib.h + * @author Jean-Philippe Lambert + * @date Mon Sep 10 11:05:09 2007 + * + * @brief Default defines for the rta library + * + * Define your own to override these. + * @see rta_configuration.h + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_STDLIB_H_ +#define _RTA_STDLIB_H_ 1 + +/** default define for memory allocation */ +#ifndef rta_malloc +#define rta_malloc malloc +#include <stdlib.h> +#endif + +/** default define for memory reallocation */ +#ifndef rta_realloc +#define rta_realloc realloc +#include <stdlib.h> +#endif + +/** default define for memory reallocation */ +#ifndef rta_zalloc +#define rta_zalloc(n) (calloc(1, (n))) +#include <stdlib.h> +#endif + +/** default define for memory deallocation */ +#ifndef rta_free +#define rta_free free +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +#endif /* _RTA_STDLIB_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_types.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_types.h new file mode 100644 index 0000000000000000000000000000000000000000..148427d5d0873c1b1f55176748c6c663862cd3e9 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_types.h @@ -0,0 +1,71 @@ +/** + * @file rta_types.h + * @author Jean-Philippe Lambert + * @date Mon Sep 10 11:05:09 2007 + * + * @brief rta_real_t type warper for float, double or long double + * + * Default is RTA_REAL_FLOAT. Define your RTA_REAL_TYPE to override these. + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_TYPES_H_ +#define _RTA_TYPES_H_ 1 + +/** default floating point precision */ +#ifndef RTA_REAL_TYPE +#define RTA_REAL_TYPE RTA_FLOAT_TYPE +#endif + +#undef RTA_FLOAT_TYPE +#define RTA_FLOAT_TYPE 1 +#undef RTA_DOUBLE_TYPE +#define RTA_DOUBLE_TYPE 2 +#undef RTA_LONG_DOUBLE_TYPE +#define RTA_LONG_DOUBLE_TYPE 3 + +#if (RTA_REAL_TYPE == RTA_FLOAT_TYPE) +#undef rta_real_t +#define rta_real_t float +#endif + +#if (RTA_REAL_TYPE == RTA_DOUBLE_TYPE) +#undef rta_real_t +#define rta_real_t double +#endif + +#if (RTA_REAL_TYPE == RTA_LONG_DOUBLE_TYPE) +#undef rta_real_t +#define rta_real_t long double +#endif + +#endif /* _RTA_TYPES_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_util.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_util.c new file mode 100644 index 0000000000000000000000000000000000000000..048d012a7017e190e950e6dc6af904fc2f43779a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_util.c @@ -0,0 +1,100 @@ +/** + * @file rta_util.c + * @author Diemo Schwarz + * @date 1.12.2009 + * + * @brief file with common support functions + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_util.h" +#include <stdlib.h> +#ifdef WIN32 +static long random(){return rand();} +#endif + +static int compint (const void *a, const void *b) +{ + return *(int *) a - *(int *) b; +} + +/* generate k random indices out of 0..n-1 in vector sample(k) + time complexity: O(k log k), space complexity O(k) + + todo: reimplement using permutation + hashing for O(k) complexity +*/ +void rta_choose_k_from_n (int k, int n, int *sample) +{ + int doubles = 99; + int i; + + if (k >= n) + { /* error: non-specified case */ + for (i = 0; i < k; i++) + sample[i] = i % n; + rta_post("illegal parameters for choose %d from %d!!!\n", k, n); + return; + } + + /* generate k random numbers with possible repetition */ + + for (i = 0; i < k; i++) + sample[i] = random() % n; + + while (doubles > 0) + { + /* sort and check for uniqueness */ + qsort(sample, k, sizeof(int), compint); + + for (i = 1, doubles = 0; i < k; i++) + if (sample[i - 1] == sample[i]) + { /* repetition: generate new random value */ + sample[i] = random() % n; + doubles++; + } + if (doubles > 0) + rta_post("choose %d from %d -> doubles %d\n", k, n, doubles); + } +} + + +/* return index i such that i is the highest i for which x < arr[i] + num !> 0 */ +int rta_find_int (int x, int num, int *arr) +{ + int i = 0; + + while (i < num && x >= arr[i]) + i++; + + return i; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_util.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_util.h new file mode 100644 index 0000000000000000000000000000000000000000..4a3f93890b13a574b2aa3588d730023c43f64f7a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/common/rta_util.h @@ -0,0 +1,108 @@ +/** + * @file rta_util.h + * @author Diemo Schwarz + * @date 1.12.2009 + * + * @brief file with common support functions + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_UTIL_H_ +#define _RTA_UTIL_H_ + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** generate k random indices out of 0..n-1 in vector sample(k) */ +void rta_choose_k_from_n (int k, int n, int *sample); + + +/** return index i such that i is the highest i for which x < arr[i] + num !> 0 */ +int rta_find_int (int x, int num, int *arr); + + + +/********************************************************************************* + * + * idefix + * + */ + +#define RTA_IDEFIX_INDEX_BITS 31 +#define RTA_IDEFIX_INDEX_MAX 2147483647 /* index is signed */ + +#define RTA_IDEFIX_FRAC_BITS 32 +#define RTA_IDEFIX_FRAC_MAX ((unsigned int) 4294967295U) +#define RTA_IDEFIX_FRAC_RANGE ((double) 4294967296.0L) + +typedef struct rta_idefix +{ + int index; + unsigned int frac; +} rta_idefix_t; + +#define rta_idefix_get_index(x) ((int)(x).index) +#define rta_idefix_get_frac(x) ((double)((x).frac) / RTA_IDEFIX_FRAC_RANGE) + +#define rta_idefix_get_float(x) ((x).index + ((double)((x).frac) / RTA_IDEFIX_FRAC_RANGE)) + +#define rta_idefix_set_int(x, i) ((x)->index = (i), (x)->frac = 0) +#define rta_idefix_set_float(x, f) ((x)->index = floor(f), (x)->frac = ((double)(f) - (x)->index) * RTA_IDEFIX_FRAC_RANGE) + +#define rta_idefix_set_zero(x) ((x)->index = 0, (x)->frac = 0) +#define rta_idefix_set_max(x) ((x)->index = RTA_IDEFIX_INDEX_MAX, (x)->frac = RTA_IDEFIX_FRAC_MAX) + +#define rta_idefix_negate(x) ((x)->index = -(x)->index - ((x)->frac > 0), (x)->frac = (RTA_IDEFIX_FRAC_MAX - (x)->frac) + 1) + +#define rta_idefix_incr(x, c) ((x)->frac += (c).frac, (x)->index += ((c).index + ((x)->frac < (c).frac))) + +#define rta_idefix_add(x, a, b) ((x)->frac = (a).frac + (b).frac, (x)->index = (a).index + ((b).index + ((x)->frac < (a).frac))) +#define rta_idefix_sub(x, a, b) ((x)->index = (a).index - ((b).index + ((a).frac < (b).frac)), (x)->frac = (a).frac - (b).frac) + +#define rta_idefix_lshift(x, c, i) ((x)->index = ((c).index << (i)) + ((c).frac >> (RTA_IDEFIX_FRAC_BITS - (i))), (x)->frac = (c).frac << (i)) + +#define rta_idefix_lt(x, c) (((x).index < (c).index) || (((x).index == (c).index) && ((x).frac < (c).frac))) +#define rta_idefix_gt(x, c) (((x).index > (c).index) || (((x).index == (c).index) && ((x).frac > (c).frac))) +#define rta_idefix_eq(x, c) (((x).index == (c).index) && ((x).frac == (c).frac)) +#define rta_idefix_is_zero(x) (((x).index == 0) && ((x).frac == 0)) + + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_UTIL_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_bands.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_bands.c new file mode 100644 index 0000000000000000000000000000000000000000..ebb60eab4410022ad093325b214cc215a32de29c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_bands.c @@ -0,0 +1,391 @@ +/** + * @file rta_bands.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Spectrum bands integrations (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * @see http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_bands.h" +#include "rta_mel.h" +#include "rta_math.h" +#include "rta_stdlib.h" + + +int rta_spectrum_to_mel_bands_weights( + rta_real_t * weights_matrix, unsigned int * weights_bounds, + const unsigned int spectrum_size, + const rta_real_t sample_rate, const unsigned int filters_number, + const rta_real_t min_freq, const rta_real_t max_freq, + const rta_real_t scale_width, + const rta_hz_to_mel_function hz_to_mel, + const rta_mel_to_hz_function mel_to_hz, + const rta_mel_t mel_type) +{ + unsigned int i,j; /* counters */ + unsigned int min_weight_index_defined; + int ret = 0; + + /* center frequency of each FFT bin */ + rta_real_t * fft_freq = (rta_real_t*) rta_malloc( + sizeof(rta_real_t) * spectrum_size); + + const rta_real_t min_mel = (*hz_to_mel)(min_freq); + const rta_real_t max_mel = (*hz_to_mel)(max_freq); + +/* Center frequencies of mel bands - uniformly spaced between limits */ + rta_real_t * filter_freq = (rta_real_t*) rta_malloc(sizeof(rta_real_t) * (filters_number + 2)); + +/* scaled filter frequencies according to <scale_width> */ + rta_real_t * scaled_filter_freq = (rta_real_t*) rta_malloc(sizeof(rta_real_t) * (filters_number + 2)); + + if(fft_freq != NULL && filter_freq != NULL && scaled_filter_freq != NULL) + { + const rta_real_t fft_size = 2. * (spectrum_size - 1.); + for(j=0; j<spectrum_size; j++) + { + fft_freq[j] = sample_rate * j / fft_size; + } + + /* There is 2 more filters as the actual number, so as to calculate */ + /* the slopes */ + for(i=0; i<filters_number + 2; i++) + { + filter_freq[i] = (*mel_to_hz)(min_mel + i / (filters_number + 1.) * + (max_mel - min_mel)); + } + + for(i=0; i<filters_number + 1; i++) + { + scaled_filter_freq[i] = filter_freq[i+1] + + scale_width * (filter_freq[i] - filter_freq[i+1]); + } + scaled_filter_freq[i] = filter_freq[i]; + + for(i=0; i<filters_number; i++) + { + min_weight_index_defined = 0; + /* Do not process the last spectrum component as it will be zeroed */ + /* later to avoid aliasing */ + for(j=0; j<spectrum_size-1; j++) + { + /* Lower slope and upper slope, intersect with each other and zero */ + weights_matrix[i*spectrum_size+j] = + rta_max(0., rta_min( + (fft_freq[j] - scaled_filter_freq[i]) / + (scaled_filter_freq[i+1] - scaled_filter_freq[i]), + (scaled_filter_freq[i+2] - fft_freq[j]) / + (scaled_filter_freq[i+2] - scaled_filter_freq[i+1]) + ) + ); + + /* Define the bounds so as to use an index <i> of the form */ + /* for(j=weights_bounds[i*2+0]; j<weights_bounds[i*2+1]; j++)) */ + /* lower bound included, upper bound excluded */ + if(weights_matrix[i*spectrum_size+j] > 0.) + { + if(min_weight_index_defined == 0) + { + min_weight_index_defined = 1; + weights_bounds[i*2] = j; + } + weights_bounds[i*2+1] = j+1; + } + } + /* empty filter */ + if(min_weight_index_defined == 0) + { + weights_bounds[i*2] = weights_bounds[i*2+1] = 0; + } + } + + /* Slaney-style mel is scaled to be approx constant E per channel */ + if(mel_type == rta_mel_slaney) + { + for(i=0; i<filters_number; i++) + { + /* process only non null values */ + for(j=weights_bounds[i*2]; j<weights_bounds[i*2+1]; j++) + { + weights_matrix[i*spectrum_size+j] *= 2. / (filter_freq[i+2] - filter_freq[i]); + } + } + } + + /* Make sure that 2nd half of FFT is zero */ + /* (We process only the middle, not the upper part) */ + /* Seems like a good idea to avoid aliasing */ + j = spectrum_size-1; + for(i=0; i<filters_number; i++) + { + weights_matrix[i*spectrum_size+j] = 0.; + } + ret = 1; + } + + if(fft_freq != NULL) + { + rta_free(fft_freq); + } + + if(filter_freq != NULL) + { + rta_free(filter_freq); + } + + if(scaled_filter_freq != NULL) + { + rta_free(scaled_filter_freq); + } + + return ret; +} + +int rta_spectrum_to_mel_bands_weights_stride( + rta_real_t * weights_matrix, const int wm_stride, + unsigned int * weights_bounds, const int wb_stride, + const unsigned int spectrum_size, + const rta_real_t sample_rate, const unsigned int filters_number, + const rta_real_t min_freq, const rta_real_t max_freq, const rta_real_t scale_width, + const rta_hz_to_mel_function hz_to_mel, + const rta_mel_to_hz_function mel_to_hz, + const rta_mel_t mel_type) +{ + unsigned int i,j; /* counters */ + unsigned int min_weight_index_defined; + int ret = 0; + +/* center frequency of each FFT bin */ + rta_real_t * fft_freq = (rta_real_t*) rta_malloc(sizeof(rta_real_t) * spectrum_size); + + const rta_real_t min_mel = (*hz_to_mel)(min_freq); + const rta_real_t max_mel = (*hz_to_mel)(max_freq); + +/* Center frequencies of mel bands - uniformly spaced between limits */ + rta_real_t * filter_freq = (rta_real_t*) rta_malloc(sizeof(rta_real_t) * (filters_number + 2)); + +/* scaled filter frequencies according to <scale_width> */ + rta_real_t * scaled_filter_freq = (rta_real_t*) rta_malloc(sizeof(rta_real_t) * (filters_number + 2)); + + if(fft_freq != NULL && filter_freq != NULL && scaled_filter_freq != NULL) + { + const rta_real_t fft_size = 2. * (spectrum_size - 1.); + for(j=0; j<spectrum_size; j++) + { + fft_freq[j] = sample_rate * j / fft_size; + } + + /* There is 2 more filters as the actual number, so as to calculate */ + /* the slopes */ + for(i=0; i<filters_number + 2; i++) + { + filter_freq[i] = (*mel_to_hz)(min_mel + i / (filters_number + 1.) * + (max_mel - min_mel)); + } + + for(i=0; i<filters_number + 2; i++) //FIXME: shouldn't be filters_number + 1, since i+1 is used in body? + { + scaled_filter_freq[i] = filter_freq[i+1] + + scale_width * (filter_freq[i] - filter_freq[i+1]); + } + + for(i=0; i<filters_number; i++) + { + min_weight_index_defined = 0; + /* Do not process the last spectrum component as it will be zeroed */ + /* later to avoid aliasing */ + for(j=0; j<spectrum_size-1; j++) + { + /* Lower slope and upper slope, intersect with each other and zero */ + weights_matrix[(i*spectrum_size+j)*wm_stride] = + rta_max(0., rta_min( + (fft_freq[j] - scaled_filter_freq[i]) / + (scaled_filter_freq[i+1] - scaled_filter_freq[i]), + (scaled_filter_freq[i+2] - fft_freq[j]) / + (scaled_filter_freq[i+2] - scaled_filter_freq[i+1]) + ) + ); + + /* Define the bounds so as to use an index <i> of the form */ + /* for(j=weights_bounds[i*2+0]; j<weights_bounds[i*2+1]; j++)) */ + /* lower bound included, upper bound excluded */ + if(weights_matrix[(i*spectrum_size+j)*wm_stride] > 0.) + { + if(min_weight_index_defined == 0) + { + min_weight_index_defined = 1; + weights_bounds[i*2*wb_stride] = j; + } + weights_bounds[(i*2+1)*wb_stride] = j+1; + } + } + /* empty filter */ + if(min_weight_index_defined == 0) + { + weights_bounds[i*2*wb_stride] = weights_bounds[(i*2+1)*wb_stride] = 0; + } + } + + /* Slaney-style mel is scaled to be approx constant E per channel */ + if(mel_type == rta_mel_slaney) + { + for(i=0; i<filters_number; i++) + { + /* process only non null values */ + for(j=weights_bounds[i*2]; j<weights_bounds[i*2+1]; j++) + { + weights_matrix[(i*spectrum_size+j)*wm_stride] *= + 2. / (filter_freq[i+2] - filter_freq[i]); + } + } + } + /* Make sure that 2nd half of FFT is zero */ + /* (We process only the middle, not the upper part) */ + /* Seems like a good idea to avoid aliasing */ + j = spectrum_size-1; + for(i=0; i<filters_number; i++) + { + weights_matrix[(i*spectrum_size+j)*wm_stride] = 0.; + } + ret = 1; + } + + if(fft_freq != NULL) + { + rta_free(fft_freq); + } + + if(filter_freq != NULL) + { + rta_free(filter_freq); + } + + if(scaled_filter_freq != NULL) + { + rta_free(scaled_filter_freq); + } + + return ret; +} + + +/* Integrate FFT bins into bands, in abs domain */ +void rta_spectrum_to_bands_abs( + rta_real_t * bands, const rta_real_t * spectrum, + const rta_real_t * weights_matrix, const unsigned int * weights_bounds, + const unsigned int spectrum_size, const unsigned int filters_number) +{ + unsigned int i,j; + + for(i=0; i<filters_number; i++) + { + bands[i] = 0.; + for(j=weights_bounds[i*2]; j<weights_bounds[i*2+1]; j++) + { + bands[i] += weights_matrix[i*spectrum_size+j] * spectrum[j]; + } + } + + return; +} + +/* Integrate FFT bins into bands, in abs domain */ +void rta_spectrum_to_bands_abs_stride( + rta_real_t * bands, const int b_stride, + const rta_real_t * spectrum, const int s_stride, + const rta_real_t * weights_matrix, const int wm_stride, + const unsigned int * weights_bounds, const int wb_stride, + const unsigned int spectrum_size, const unsigned int filters_number) +{ + unsigned int i,j; + + for(i=0; i<filters_number; i++) + { + bands[i*b_stride] = 0.; + for(j=weights_bounds[i*2*wb_stride]; j<weights_bounds[(i*2+1)*wb_stride]; j++) + { + bands[i*b_stride] += + weights_matrix[(i*spectrum_size+j)*wm_stride] * spectrum[j*s_stride]; + } + } + + return; +} + +/* Integrate FFT bins into bands, in abs^2 domain */ +void rta_spectrum_to_bands_square_abs( + rta_real_t * bands, const rta_real_t * spectrum, + const rta_real_t * weights_matrix, const unsigned int * weights_bounds, + const unsigned int spectrum_size, const unsigned int filters_number) +{ + unsigned int i,j; + + for(i=0; i<filters_number; i++) + { + bands[i] = 0.; + for(j=weights_bounds[i*2]; j<weights_bounds[i*2+1]; j++) + { + bands[i] += weights_matrix[i*spectrum_size+j] * rta_sqrt(spectrum[j]); + } + bands[i] = rta_pow(bands[i], 2); + } + + return; +} + +/* Integrate FFT bins into bands, in abs^2 domain */ +void rta_spectrum_to_bands_square_abs_stride( + rta_real_t * bands, const int b_stride, + const rta_real_t * spectrum, const int s_stride, + const rta_real_t * weights_matrix, const int wm_stride, + const unsigned int * weights_bounds, const int wb_stride, + const unsigned int spectrum_size, const unsigned int filters_number) +{ + unsigned int i,j; + + for(i=0; i<filters_number; i++) + { + bands[i*b_stride] = 0.; + for(j=weights_bounds[i*2*wb_stride]; j<weights_bounds[(i*2+1)*wb_stride]; j++) + { + bands[i*b_stride] += weights_matrix[(i*spectrum_size+j)*wm_stride] * + rta_sqrt(spectrum[j*s_stride]); + } + bands[i*b_stride] = rta_pow(bands[i*b_stride], 2); + } + + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_bands.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_bands.h new file mode 100644 index 0000000000000000000000000000000000000000..6d5095a40a77fd42e4cba0fb5e4cedf1c742d5e2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_bands.h @@ -0,0 +1,276 @@ +/** + * @file rta_bands.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Spectrum bands integrations (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * @see http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_BANDS_H_ +#define _RTA_BANDS_H_ 1 + +#include "rta.h" +#include "rta_mel.h" /**< mel types and functions for mel bands */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + rta_bands_sum = 0, /**< simple sum between specified bins */ + rta_bands_bark = 1, + rta_bands_mel = 2, + rta_bands_htk_mel = 3, + rta_bands_feacalc_mel = 4 +} rta_bands_t; + +/** Integrate FFT bins into Mel bins, in abs or abs^2 domains */ +typedef enum +{ + rta_bands_abs_integration = 0, /**< sumpower = 0 (cf. Dan Ellis) */ + rta_bands_square_abs_integration = 1 +} rta_integration_t; + + +/* from fft2melmx.m */ + +/** + * Generate a matrix of weights 'weights_matrix' to combine a power + * spectrum into mel bands. + * As this matrix is rather sparse, generate also a bounds matrix + * 'weights_bounds', to avoid further null multiplications. + * + * You can exactly duplicate the mel matrix in Slaney's mfcc.m as + * ret = rta_spectrum_to_mel_bands_weights(weights_matrix, weights_bounds, + * 512, 8000., 40, 133., 6855.5, 1., + * rta_hz_to_mel_slaney, rta_mel_to_hz_slaney, rta_slaney_mel); + * + * Temporary memory allocation (and deallocation) is done inside this function. + * \see rta_stdlib.h + * + * @param weights_matrix size is 'filters_number'*'spectrum_size' + * @param weights_bounds size is 'filters_number'*2. + * Define the bounds for each filter 'f' so as to use an index 'i' of the form + * for(i=weights_bounds[f*2+0]; i<weights_bounds[f*2+1]; i++) + * lower bound included, upper bound excluded + * @param spectrum_size points number of the power spectrum (which is + * the complex square module of the FFT, so 'spectrum_size' is ('fft_size'/2.)+1.) + * @param sample_rate of the signal corresponding to the power spectrum + * @param filters_number number of output mel bands + * @param min_freq in Hz. + * default is 0, but 133.33 is a common standard (to skip LF). + * @param max_freq in Hertz + * @param scale_width frequencies are scale by this factor (generally + * 1., which means no scale) + * @param hz_to_mel function used for conversion + * @param mel_to_hz function used for conversion (inverse of hz_to_mel) + * @param mel_type slaney_mel is scaled to be approx constant E per + * channel, not HTK. Integration windows peak at 1 for HTK, not sum to + * 1 (as for Slaney) + * + * @return 1 on success 0 on fail + */ +int rta_spectrum_to_mel_bands_weights( + rta_real_t * weights_matrix, unsigned int * weights_bounds, + const unsigned int spectrum_size, + const rta_real_t sample_rate, const unsigned int filters_number, + const rta_real_t min_freq, const rta_real_t max_freq, const rta_real_t scale_width, + const rta_hz_to_mel_function hz_to_mel, + const rta_mel_to_hz_function mel_to_hz, + const rta_mel_t mel_type); + +/** + * Generate a matrix of weights 'weights_matrix' to combine a power + * spectrum into mel bands. + * As this matrix is rather sparse, generate also a bounds matrix + * 'weights_bounds', to avoid further null multiplications. + * + * You can exactly duplicate the mel matrix in Slaney's mfcc.m as + * ret = rta_spectrum_to_mel_bands_weights(weights_matrix, weights_bounds, + * 512, 8000., 40, 133., 6855.5, 1., + * rta_hz_to_mel_slaney, rta_mel_to_hz_slaney, rta_slaney_mel); + * + * Temporary memory allocation (and deallocation) is done inside this function. + * \see rta_memory.h + * + * @param weights_matrix size is 'filters_number'*'spectrum_size' + * @param wm_stride is 'weights_matrix' stride + * @param weights_bounds size is 'filters_number'*2. + * Define the bounds for each filter 'f' so as to use an index 'i' of the form + * for(i=weights_bounds[f*2+0]; i<weights_bounds[f*2+1]; i++) + * lower bound included, upper bound excluded + * @param wb_stride is 'weights_bounds' stride + * @param spectrum_size points number of the power spectrum (which is + * the complex square module of the FFT, so 'spectrum_size' is ('fft_size'/2.)+1.) + * @param sample_rate of the signal corresponding to the power spectrum + * @param filters_number number of output mel bands + * @param min_freq in Hertz. + * default is 0, but 133.33 is a common standard (to skip LF). + * @param max_freq in Hertz + * @param scale_width frequencies are scale by this factor (generally + * 1., which means no scale) + * @param hz_to_mel function used for conversion + * @param mel_to_hz function used for conversion (inverse of hz_to_mel) + * @param mel_type slaney_mel is scaled to be approx constant E per + * channel, not HTK. Integration windows peak at 1 for HTK, not sum to + * 1 (as for Slaney) + * + * @return 1 on success 0 on fail + */ +int rta_spectrum_to_mel_bands_weights_stride( + rta_real_t * weights_matrix, const int wm_stride, + unsigned int * weights_bounds, const int wb_stride, + const unsigned int spectrum_size, + const rta_real_t sample_rate, const unsigned int filters_number, + const rta_real_t min_freq, const rta_real_t max_freq, const rta_real_t scale_width, + const rta_hz_to_mel_function hz_to_mel, + const rta_mel_to_hz_function mel_to_hz, + const rta_mel_t mel_type); + +/*from audspec.m */ + +/** + * function pointer to avoid tests during bands integration + * \see rta_spectrum_to_bands_abs + * \see rta_spectrum_to_bands_square_abs + */ +typedef void (*rta_spectrum_to_bands_function) +(rta_real_t *, const rta_real_t *, const rta_real_t *, + const unsigned int *, const unsigned int, const unsigned int); + +/** + * function pointer to avoid tests during bands integration + * \see rta_spectrum_to_bands_abs_stride + * \see rta_spectrum_to_bands_square_abs_stride + */ +typedef void (*rta_spectrum_to_bands_stride_function) +(rta_real_t *, const int, const rta_real_t *, const int, const rta_real_t *, const int, + const unsigned int *, const int, + const unsigned int, const unsigned int); + + +/** + * Integrate amplitude spectrum into bands, in abs domain + * 'bands' = 'weights_matrix'*'spectrum' + * + * @param bands size is 'filters_number' + * @param spectrum size is 'spectrum_size' + * @param weights_matrix size is 'filters_number'*'spectrum_size' + * @param weights_bounds size is 'filters_number'*2. + * @param spectrum_size points number of the power spectrum (which is + * the complex square module of the FFT, so 'spectrum_size' is ('fft_size'/2.)+1.) + * @param filters_number number of output bands + * + */ +void rta_spectrum_to_bands_abs( + rta_real_t * bands, const rta_real_t * spectrum, + const rta_real_t * weights_matrix, const unsigned int * weights_bounds, + const unsigned int spectrum_size, const unsigned int filters_number); + +/** + * Integrate amplitude spectrum into bands, in abs domain + * 'bands' = 'weights_matrix'*'spectrum' + * + * @param bands size is 'filters_number' + * @param b_stride is 'bands' stride + * @param spectrum size is 'spectrum_size' + * @param s_stride is 'spectrum' stride + * @param weights_matrix size is 'filters_number'*'spectrum_size' + * @param wm_stride is 'weights_matrix' stride + * @param weights_bounds size is 'filters_number'*2. + * @param wb_stride is 'weights_bounds' stride + * @param spectrum_size points number of the power spectrum (which is + * the complex square module of the FFT, so 'spectrum_size' is ('fft_size'/2.)+1.) + * @param filters_number number of output bands + * + */ +void rta_spectrum_to_bands_abs_stride( + rta_real_t * bands, const int b_stride, + const rta_real_t * spectrum, const int s_stride, + const rta_real_t * weights_matrix, const int wm_stride, + const unsigned int * weights_bounds, const int wb_stride, + const unsigned int spectrum_size, const unsigned int filters_number); + +/** + * Integrate power spectrum into bands, in abs^2 domain + * 'bands' = ('weights_matrix'*sqrt('spectrum')).^2 + * + * @param bands size is 'filters_number' + * @param spectrum size is 'spectrum_size' + * @param weights_matrix size is 'filters_number'*'spectrum_size' + * @param weights_bounds size is 'filters_number'*2. + * @param spectrum_size points number of the power spectrum (which is + * the complex square module of the FFT, so 'spectrum_size' is ('fft_size'/2.)+1.) + * @param filters_number number of output bands + * + */ +void rta_spectrum_to_bands_square_abs( + rta_real_t * bands, const rta_real_t * spectrum, + const rta_real_t * weights_matrix, const unsigned int * weights_bounds, + const unsigned int spectrum_size, const unsigned int filters_number); + +/** + * Integrate power spectrum into bands, in abs^2 domain + * 'bands' = ('weights_matrix'*sqrt('spectrum')).^2 + * + * @param bands size is 'filters_number' + * @param b_stride is 'bands' stride + * @param spectrum size is 'spectrum_size' + * @param s_stride is 'spectrum' stride + * @param weights_matrix size is 'filters_number'*'spectrum_size' + * @param wm_stride is 'weights_matrix' stride + * @param weights_bounds size is 'filters_number'*2. + * @param wb_stride is 'weights_bounds' stride + * @param spectrum_size points number of the power spectrum (which is + * the complex square module of the FFT, so 'spectrum_size' is ('fft_size'/2.)+1.) + * @param filters_number number of output bands + * + */ +void rta_spectrum_to_bands_square_abs_stride( + rta_real_t * bands, const int b_stride, + const rta_real_t * spectrum, const int s_stride, + const rta_real_t * weights_matrix, const int wm_stride, + const unsigned int * weights_bounds, const int wb_stride, + const unsigned int spectrum_size, const unsigned int filters_number); + + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_BANDS_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_biquad.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_biquad.c new file mode 100644 index 0000000000000000000000000000000000000000..0cc75257acd1ff815db9fb1d9f782b6a86813382 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_biquad.c @@ -0,0 +1,768 @@ +/** + * @file rta_biquad.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Aug 29 12:38:46 2008 + * + * @brief Biquad filter and coefficients calculation + * + * Based on the "Cookbook formulae for audio EQ biquad filter + * coefficients" by Robert Bristow-Johnson + * + * @copyright + * Copyright (C) 2008 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_biquad.h" +#include "rta_filter.h" /* filter types */ +#include "rta_math.h" /* rta_sin, rta_cos, M_PI */ + +/* y(n) = b0 x(n) + b1 x(n-1) + b2 x(n-2) */ +/* - a1 x(n-1) - a2 x(n-2) */ + +/* note that MaxMSP biquad~ swaps the names for a and b */ + +/* f0 is normalised by the nyquist frequency */ +/* q must be > 0. */ +/* gain must be > 0. and is linear */ + +/* when there is no gain parameter, one can simply multiply the b + * coefficients by a (linear) gain */ + +/* a0 is always 1. as each coefficient is normalised by a0, including a0 */ + +/* a1 is a[0] and a2 is a[1] */ + + +/* LPF: H(s) = 1 / (s^2 + s/Q + 1) */ +void rta_biquad_lowpass_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha) * a0_inv; + + b[0] = ((1. - c) * 0.5) * a0_inv; + b[1] = (1. - c) * a0_inv; + b[2] = b[0]; + + return; +} + +/* LPF: H(s) = 1 / (s^2 + s/Q + 1) */ +void rta_biquad_lowpass_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha) * a0_inv; + + b[0] = ((1. - c) * 0.5) * a0_inv; + b[b_stride] = (1. - c) * a0_inv; + b[2*b_stride] = b[0]; + + return; +} + +/* HPF: H(s) = s^2 / (s^2 + s/Q + 1) */ +void rta_biquad_highpass_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha) * a0_inv; + + b[0] = ((1. + c) * 0.5) * a0_inv; + b[1] = (-1. - c) * a0_inv; + b[2] = b[0]; + + return; +} + +/* HPF: H(s) = s^2 / (s^2 + s/Q + 1) */ +void rta_biquad_highpass_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha) * a0_inv; + + b[0] = ((1. + c) * 0.5) * a0_inv; + b[b_stride] = (-1. - c) * a0_inv; + b[2*b_stride] = b[0]; + + return; +} + +/* BPF: H(s) = s / (s^2 + s/Q + 1) (constant skirt gain, peak gain = Q) */ +void rta_biquad_bandpass_constant_skirt_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, + const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t s = rta_sin(w0); + const rta_real_t alpha = s / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha) * a0_inv; + + b[0] = (s * 0.5) * a0_inv; + b[1] = 0.; + b[2] = -b[0]; + + return; +} + +/* BPF: H(s) = s / (s^2 + s/Q + 1) (constant skirt gain, peak gain = Q) */ +void rta_biquad_bandpass_constant_skirt_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, + const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t s = rta_sin(w0); + const rta_real_t alpha = s / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha) * a0_inv; + + b[0] = (s * 0.5) * a0_inv; + b[b_stride] = 0.; + b[2*b_stride] = -b[0]; + + return; +} + +/* BPF: H(s) = (s/Q) / (s^2 + s/Q + 1) (constant 0 dB peak gain) */ +void rta_biquad_bandpass_constant_peak_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, + const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha) * a0_inv; + + b[0] = alpha * a0_inv; + b[1] = 0.; + b[2] = -b[0]; + + return; +} + +/* BPF: H(s) = (s/Q) / (s^2 + s/Q + 1) (constant 0 dB peak gain) */ +void rta_biquad_bandpass_constant_peak_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, + const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha) * a0_inv; + + b[0] = alpha * a0_inv; + b[b_stride] = 0.; + b[2*b_stride] = -b[0]; + + return; +} + +/* notch: H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */ +void rta_biquad_notch_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha) * a0_inv; + + b[0] = a0_inv; + b[1] = a[0]; + b[2] = b[0]; + + return; +} + +/* notch: H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */ +void rta_biquad_notch_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha) * a0_inv; + + b[0] = a0_inv; + b[b_stride] = a[0]; + b[2*b_stride] = b[0]; + + return; +} + +/* APF: H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */ +void rta_biquad_allpass_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha) * a0_inv; + + b[0] = a[1]; + b[1] = a[0]; + b[2] = 1.; + + return; +} + +/* APF: H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */ +void rta_biquad_allpass_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q) +{ + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha) * a0_inv; + + b[0] = a[a_stride]; + b[b_stride] = a[0]; + b[2*b_stride] = 1.; + + return; +} + +/* peakingEQ: H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */ +/* A = sqrt( 10^(dBgain/20) ) = 10^(dBgain/40) */ +/* gain is linear here */ +void rta_biquad_peaking_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + const rta_real_t g = rta_sqrt(gain); + const rta_real_t g_inv = 1. / g; + + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha * g_inv); + + a[0] = (-2. * c) * a0_inv; + a[1] = (1. - alpha * g_inv) * a0_inv; + + b[0] = (1. + alpha * g) * a0_inv; + b[1] = a[0]; + b[2] = (1. - alpha * g) * a0_inv; + + return; +} + +/* peakingEQ: H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */ +/* A = sqrt( 10^(dBgain/20) ) = 10^(dBgain/40) */ +/* gain is linear here */ +void rta_biquad_peaking_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + const rta_real_t g = rta_sqrt(gain); + const rta_real_t g_inv = 1. / g; + + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha = rta_sin(w0) / (2. * q); + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / (1. + alpha * g_inv); + + a[0] = (-2. * c) * a0_inv; + a[a_stride] = (1. - alpha * g_inv) * a0_inv; + + b[0] = (1. + alpha * g) * a0_inv; + b[b_stride] = a[0]; + b[2*b_stride] = (1. - alpha * g) * a0_inv; + + return; +} + +/* lowShelf: H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */ +/* A = sqrt( 10^(dBgain/20) ) = 10^(dBgain/40) */ +/* gain is linear here */ +void rta_biquad_lowshelf_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + const rta_real_t g = rta_sqrt(gain); + + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha_2_sqrtg = rta_sin(w0) * rta_sqrt(g) / q ; + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / + ( (g+1.) + (g-1.) * c + alpha_2_sqrtg); + + a[0] = (-2. * ( (g-1.) + (g+1.) * c ) ) * a0_inv; + a[1] = ( (g+1.) + (g-1.) * c - alpha_2_sqrtg ) * a0_inv; + + b[0] = ( g * ( (g+1.) - (g-1.) * c + alpha_2_sqrtg) ) * a0_inv; + b[1] = ( 2. * g * ( (g-1.) - (g+1.) * c ) ) * a0_inv; + b[2] = ( g * ( (g+1.) - (g-1.) * c - alpha_2_sqrtg) ) * a0_inv; + + return; +} + +/* lowShelf: H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */ +/* A = sqrt( 10^(dBgain/20) ) = 10^(dBgain/40) */ +/* gain is linear here */ +void rta_biquad_lowshelf_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + const rta_real_t g = rta_sqrt(gain); + + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha_2_sqrtg = rta_sin(w0) * rta_sqrt(g) / q ; + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / + ( (g+1.) + (g-1.) * c + alpha_2_sqrtg); + + a[0] = (-2. * ( (g-1.) + (g+1.) * c ) ) * a0_inv; + a[a_stride] = ( (g+1.) + (g-1.) * c - alpha_2_sqrtg ) * a0_inv; + + b[0] = ( g * ( (g+1.) - (g-1.) * c + alpha_2_sqrtg) ) * a0_inv; + b[b_stride] = ( 2. * g * ( (g-1.) - (g+1.) * c ) ) * a0_inv; + b[2*b_stride] = ( g * ( (g+1.) - (g-1.) * c - alpha_2_sqrtg) ) * a0_inv; + + return; +} + +/* highShelf: H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */ +/* A = sqrt( 10^(dBgain/20) ) = 10^(dBgain/40) */ +/* gain is linear here */ +void rta_biquad_highshelf_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + const rta_real_t g = rta_sqrt(gain); + + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha_2_sqrtg = rta_sin(w0) * rta_sqrt(g) / q ; + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / + ( (g+1.) - (g-1.) * c + alpha_2_sqrtg); + + a[0] = ( 2. * ( (g-1.) - (g+1.) * c ) ) * a0_inv; + a[1] = ( (g+1.) - (g-1.) * c - alpha_2_sqrtg ) * a0_inv; + + b[0] = ( g * ( (g+1.) + (g-1.) * c + alpha_2_sqrtg) ) * a0_inv; + b[1] = (-2. * g * ( (g-1.) + (g+1.) * c ) ) * a0_inv; + b[2] = ( g * ( (g+1.) + (g-1.) * c - alpha_2_sqrtg) ) * a0_inv; + + return; +} + +/* highShelf: H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */ +/* A = sqrt( 10^(dBgain/20) ) = 10^(dBgain/40) */ +/* gain is linear here */ +void rta_biquad_highshelf_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + const rta_real_t g = rta_sqrt(gain); + + const rta_real_t w0 = M_PI * f0; + const rta_real_t alpha_2_sqrtg = rta_sin(w0) * rta_sqrt(g) / q ; + const rta_real_t c = rta_cos(w0); + + const rta_real_t a0_inv = 1. / + ( (g+1.) - (g-1.) * c + alpha_2_sqrtg); + + a[0] = ( 2. * ( (g-1.) - (g+1.) * c ) ) * a0_inv; + a[a_stride] = ( (g+1.) - (g-1.) * c - alpha_2_sqrtg ) * a0_inv; + + b[0] = ( g * ( (g+1.) + (g-1.) * c + alpha_2_sqrtg) ) * a0_inv; + b[b_stride] = (-2. * g * ( (g-1.) + (g+1.) * c ) ) * a0_inv; + b[2*b_stride] = ( g * ( (g+1.) + (g-1.) * c - alpha_2_sqrtg) ) * a0_inv; + + return; +} + +/* helper */ +void rta_biquad_coefs(rta_real_t * b, rta_real_t * a, + const rta_filter_t type, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + + switch(type) + { + case rta_lowpass: + rta_biquad_lowpass_coefs(b, a, f0, q); + break; + + case rta_highpass: + rta_biquad_highpass_coefs(b, a, f0, q); + break; + + case rta_bandpass_constant_skirt: + rta_biquad_bandpass_constant_skirt_coefs(b, a, f0, q); + break; + + case rta_bandpass_constant_peak: + rta_biquad_bandpass_constant_peak_coefs(b, a, f0, q); + break; + + case rta_notch: + rta_biquad_notch_coefs(b, a, f0, q); + break; + + case rta_allpass: + rta_biquad_allpass_coefs(b, a, f0, q); + break; + + case rta_peaking: + rta_biquad_peaking_coefs(b, a, f0, q, gain); + break; + + case rta_lowshelf: + rta_biquad_lowshelf_coefs(b, a, f0, q, gain); + break; + + case rta_highshelf: + rta_biquad_highshelf_coefs(b, a, f0, q, gain); + break; + } + + switch(type) + { + case rta_lowpass: + case rta_highpass: + case rta_bandpass_constant_skirt: + case rta_bandpass_constant_peak: + case rta_notch: + case rta_allpass: + + if(gain != 1.) + { + b[0] *= gain; + b[1] *= gain; + b[2] *= gain; + } + break; + + /* gain is already integrated for the following */ + case rta_peaking: + case rta_lowshelf: + case rta_highshelf: + break; + } + + return; +} + +/* helper */ +void rta_biquad_coefs_stride(rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_filter_t type, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain) +{ + + switch(type) + { + case rta_lowpass: + rta_biquad_lowpass_coefs_stride(b, b_stride, a, a_stride, f0, q); + break; + + case rta_highpass: + rta_biquad_highpass_coefs_stride(b, b_stride, a, a_stride, f0, q); + break; + + case rta_bandpass_constant_skirt: + rta_biquad_bandpass_constant_skirt_coefs_stride(b, b_stride, a, a_stride, + f0, q); + break; + + case rta_bandpass_constant_peak: + + rta_biquad_bandpass_constant_peak_coefs_stride(b, b_stride, a, a_stride, + f0, q); + break; + + case rta_notch: + rta_biquad_notch_coefs_stride(b, b_stride, a, a_stride, f0, q); + break; + + case rta_allpass: + rta_biquad_allpass_coefs_stride(b, b_stride, a, a_stride, f0, q); + break; + + case rta_peaking: + rta_biquad_peaking_coefs_stride(b, b_stride, a, a_stride, f0, q, gain); + break; + + case rta_lowshelf: + rta_biquad_lowshelf_coefs_stride(b, b_stride, a, a_stride, f0, q, gain); + break; + + case rta_highshelf: + rta_biquad_highshelf_coefs_stride(b, b_stride, a, a_stride, f0, q, gain); + break; + } + + switch(type) + { + case rta_lowpass: + case rta_highpass: + case rta_bandpass_constant_skirt: + case rta_bandpass_constant_peak: + case rta_notch: + case rta_allpass: + + if(gain != 1.) + { + b[0] *= gain; + b[b_stride] *= gain; + b[2*b_stride] *= gain; + } + break; + + /* gain is already integrated for the following */ + case rta_peaking: + case rta_lowshelf: + case rta_highshelf: + break; + } + + return; +} + +/* direct form I */ +/* a0 = 1, a1 = a[0], a2 = a[1] */ +/* 4 states (in that order): x(n-1), x(n-2), y(n-1), y(n-2) */ +inline rta_real_t rta_biquad_df1(const rta_real_t x, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states) +{ + rta_real_t y = b[0] * x + + b[1] * states[0] + b[2] * states[1] - a[0] * states[2] - a[1] * states[3]; + + states[1] = states[0]; + states[0] = x; + + states[3] = states[2]; + states[2] = y; + + return y; +} + +/* transposed direct form II */ +/* a0 = 1, a1 = a[0], a2 = a[1] */ +/* 2 states */ +inline rta_real_t rta_biquad_df2t(const rta_real_t x, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states) +{ + rta_real_t y = b[0] * x + states[0]; + states[0] = b[1] * x - a[0] * y + states[1]; + states[1] = b[2] * x - a[1] * y; + + return y; +} + +/* direct form I */ +/* a0 = 1, a1 = a[0], a2 = a[1] */ +/* 4 states (in that order): x(n-1), x(n-2), y(n-1), y(n-2) */ +inline rta_real_t rta_biquad_df1_stride( + const rta_real_t x, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride) +{ + rta_real_t y = b[0] * x + + b[b_stride] * states[0] + b[2*b_stride] * states[s_stride] - + a[0] * states[2*s_stride] - a[a_stride] * states[3*s_stride]; + + states[s_stride] = states[0]; + states[0] = x; + + states[3*s_stride] = states[2*s_stride]; + states[2*s_stride] = y; + + return y; +} + +/* transposed direct form II */ +/* a0 = 1, a1 = a[0], a2 = a[1] */ +/* 2 states */ +inline rta_real_t rta_biquad_df2t_stride( + const rta_real_t x, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride) +{ + rta_real_t y = b[0] * x + states[0]; + states[0] = b[b_stride] * x - a[0] * y + states[s_stride]; + states[s_stride] = b[2*b_stride] * x - a[a_stride] * y; + + return y; +} + +void rta_biquad_df1_vector(rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states) +{ + unsigned int i; + + for(i = 0; i < x_size; i++) + { + y[i] = rta_biquad_df1(x[i], b, a, states); + } + + + return; +} + +void rta_biquad_df2t_vector(rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states) +{ + unsigned int i; + + for(i = 0; i < x_size; i++) + { + y[i] = rta_biquad_df2t(x[i], b, a, states); + } + + + return; +} + +void rta_biquad_df1_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride) +{ + int ix, iy; + + for(ix = 0, iy = 0; + ix < x_size*x_stride; + ix += x_stride, iy += y_stride) + { + y[iy] = rta_biquad_df1_stride( + x[ix], b, b_stride, a, a_stride, states, s_stride); + } + + return; +} + +void rta_biquad_df2t_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride) +{ + int ix, iy; + + for(ix = 0, iy = 0; + ix < x_size*x_stride; + ix += x_stride, iy += y_stride) + { + y[iy] = rta_biquad_df2t_stride( + x[ix], b, b_stride, a, a_stride, states, s_stride); + } + + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_biquad.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_biquad.h new file mode 100644 index 0000000000000000000000000000000000000000..286e990878847e69a000cdc49a791879e456c9c7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_biquad.h @@ -0,0 +1,727 @@ +/** + * @file rta_biquad.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Aug 29 12:38:46 2008 + * + * @brief Biquad filter and coefficients calculations. + * + * Based on the "Cookbook formulae for audio EQ biquad filter + * coefficients" by Robert Bristow-Johnson. + * + * @htmlonly <pre> + * y(n) = b0 x(n) + b1 x(n-1) + b2 x(n-2) + * - a1 y(n-1) - a2 y(n-2) + * </pre> @endhtmlonly + * + * (This is Matlab convention, MaxMSP biquad~ swaps the names for a + * and b.) + * + * a0 is always 1. as each coefficient is normalised by a0, including + * a0. + * + * For every function, a1 is a[0] and a2 is a[1]. b0 is b[0], b1 is + * b[1] and b2 is b[2]. + * + * @copyright + * Copyright (C) 2008 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause)} + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_BIQUAD_H_ +#define _RTA_BIQUAD_H_ 1 + +#include "rta.h" +#include "rta_filter.h" /* filter types */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#define inline +#endif + +/** + * Biquad coefficients for a low-pass filter. + * H(s) = 1 / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency: the filter is closed if f0 == 0. and open if f0 == 1. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + */ +void rta_biquad_lowpass_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for a low-pass filter. + * H(s) = 1 / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency: the filter is closed if f0 == 0. and open if f0 == 1. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + */ +void rta_biquad_lowpass_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for a high-pass filter. + * H(s) = s^2 / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency: the filter is closed if f0 == 1. and open if f0 == 0. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + */ +void rta_biquad_highpass_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for a high-pass filter. + * H(s) = s^2 / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency: the filter is closed if f0 == 1. and open if f0 == 0. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + */ +void rta_biquad_highpass_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for a band-pass filter with constant skirt. The + * peak gain is 'q'. + * H(s) = s / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_bandpass_constant_skirt_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, + const rta_real_t q); + +/** + * Biquad coefficients for a band-pass filter with constant skirt. The + * peak gain is 'q'. + * H(s) = s / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_bandpass_constant_skirt_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, + const rta_real_t q); + +/** + * Biquad coefficients for a band-pass filter with constant 0 dB peak. + * H(s) = (s/q) / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_bandpass_constant_peak_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, + const rta_real_t q); + +/** + * Biquad coefficients for a band-pass filter with constant 0 dB peak. + * H(s) = (s/q) / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_bandpass_constant_peak_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, + const rta_real_t q); + +/** + * Biquad coefficients for a notch filter. + * H(s) = (s^2 + 1) / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_notch_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for a notch filter. + * H(s) = (s^2 + 1) / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_notch_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for an all-pass filter. + * H(s) = (s^2 - s/q + 1) / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_allpass_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for an all-pass filter. + * H(s) = (s^2 - s/q + 1) / (s^2 + s/q + 1) + * + * @param b is a vector of feed-forward coefficients. To apply a + * (linear) gain, simply multiply the b coefficients by the gain. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + */ +void rta_biquad_allpass_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q); + +/** + * Biquad coefficients for an peaking filter. + * H(s) = (s^2 + s*(g/q) + 1) / (s^2 + s/(g*q) + 1), + * g = sqrt('gain'), + * 'gain' is linear. + * + * @param b is a vector of feed-forward coefficients + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + * @param gain is linear and must be > 0. + */ +void rta_biquad_peaking_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + +/** + * Biquad coefficients for an peaking filter. + * H(s) = (s^2 + s*(g/q) + 1) / (s^2 + s/(g*q) + 1), + * g = sqrt('gain'), + * 'gain' is linear. + * + * @param b is a vector of feed-forward coefficients + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. + * @param gain is linear and must be > 0. + */ +void rta_biquad_peaking_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + +/** + * Biquad coefficients for an low-shelf filter. + * H(s) = g * (s^2 + (sqrt(g)/q)*s + g)/(g*s^2 + (sqrt(g)/q)*s + 1) + * g = sqrt('gain'), + * 'gain' is linear. + * + * @param b is a vector of feed-forward coefficients + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + * @param gain is linear and must be > 0. + */ +void rta_biquad_lowshelf_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + +/** + * Biquad coefficients for an low-shelf filter. + * H(s) = g * (s^2 + (sqrt(g)/q)*s + g)/(g*s^2 + (sqrt(g)/q)*s + 1) + * g = sqrt('gain'), + * 'gain' is linear. + * + * @param b is a vector of feed-forward coefficients + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + * @param gain is linear and must be > 0. + */ +void rta_biquad_lowshelf_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + +/** + * Biquad coefficients for an high-shelf filter. + * H(s) = g * (g*s^2 + (sqrt(g)/q)*s + 1)/(s^2 + (sqrt(g)/q)*s + g) + * g = sqrt('gain'), + * 'gain' is linear. + * + * @param b is a vector of feed-forward coefficients + * @param a is a vector of feed-backward coefficients + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + * @param gain is linear and must be > 0. + */ +void rta_biquad_highshelf_coefs(rta_real_t * b, rta_real_t * a, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + +/** + * Biquad coefficients for an high-shelf filter. + * H(s) = g * (g*s^2 + (sqrt(g)/q)*s + 1)/(s^2 + (sqrt(g)/q)*s + g) + * g = sqrt('gain'), + * 'gain' is linear. + * + * @param b is a vector of feed-forward coefficients + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response. + * @param gain is linear and must be > 0. + */ +void rta_biquad_highshelf_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + +/** + * Helper function calling the proper biquad coefficients calculation + * function, depending on the filter type. + * + * @param b is a vector of feed-forward coefficients + * @param a is a vector of feed-backward coefficients + * @param type can be: + * <pre> + * lowpass: H(s) = 1 / (s^2 + s/q + 1) + * highpass: H(s) = s^2 / (s^2 + s/q + 1) + * bandpass_cst_skirt: H(s) = s / (s^2 + s/q + 1) + * (The peak gain is q*gain) + * bandpass_cst_peak: H(s) = (s/q) / (s^2 + s/q + 1) + * (The peak gain is gain) + * notch: H(s) = (s^2 + 1) / (s^2 + s/q + 1) + * allpass: H(s) = (s^2 - s/q + 1) / (s^2 + s/q + 1) + * peaking: H(s) = (s^2 + s*(g/q) + 1) / (s^2 + s/(g*q) + 1), + * with g = sqrt(gain) + * lowshelf: H(s) = g * (s^2 + (sqrt(g)/q)*s + g)/ + * (g*s^2 + (sqrt(g)/q)*s + 1) + * with g = sqrt(gain) + * highshelf: H(s) = g * (g*s^2 + (sqrt(g)/q)*s + 1)/ + * (s^2 + (sqrt(g)/q)*s + g) + * with g = sqrt(gain) + * </pre> + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response + * for lowpass, highpass, lowshelf and highshelf types. + * @param gain is linear and must be > 0. + */ +void rta_biquad_coefs(rta_real_t * b, rta_real_t * a, + const rta_filter_t type, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + + +/** + * Helper function calling the proper biquad coefficients calculation + * function, depending on the filter type. + * + * @param b is a vector of feed-forward coefficients + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients + * @param a_stride is 'a' stride + * @param type can be: + * <pre> + * lowpass: H(s) = 1 / (s^2 + s/q + 1) + * highpass: H(s) = s^2 / (s^2 + s/q + 1) + * bandpass_cst_skirt: H(s) = s / (s^2 + s/q + 1) + * (The peak gain is q*gain) + * bandpass_cst_peak: H(s) = (s/q) / (s^2 + s/q + 1) + * (The peak gain is gain) + * notch: H(s) = (s^2 + 1) / (s^2 + s/q + 1) + * allpass: H(s) = (s^2 - s/q + 1) / (s^2 + s/q + 1) + * peaking: H(s) = (s^2 + s*(g/q) + 1) / (s^2 + s/(g*q) + 1), + * with g = sqrt(gain) + * lowshelf: H(s) = g * (s^2 + (sqrt(g)/q)*s + g)/ + * (g*s^2 + (sqrt(g)/q)*s + 1) + * with g = sqrt(gain) + * highshelf: H(s) = g * (g*s^2 + (sqrt(g)/q)*s + 1)/ + * (s^2 + (sqrt(g)/q)*s + g) + * with g = sqrt(gain) + * </pre> + * @param f0 is the cutoff frequency, normalised by the nyquist + * frequency. + * @param q must be > 0. and is generally >= 0.5 for audio + * filtering. q <= 1./sqrt(2.) is the limit for monotonic response + * for lowpass, highpass, lowshelf and highshelf types. + * @param gain is linear and must be > 0. + */ +void rta_biquad_coefs_stride( + rta_real_t * b, const int b_stride, + rta_real_t * a, const int a_stride, + const rta_filter_t type, + const rta_real_t f0, const rta_real_t q, + const rta_real_t gain); + + +/** + * Biquad computation, using a direct form I. + * + * <pre> + * x b0 y + * --------+----->----->( + )-------->-----+-------> + * | ^ ^ ^ ^ | + * V b1 / / \ \ -a1 V + * [x-1]--->----/ / \ \------<---[y-1] + * | / \ | + * V b2 / \ -a2 V + * [x-2]--->---/ \-----<---[y-2] + * + * </pre> + * + * @param x is an input sample + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param states is a vector of 4 elements: for an input 'x' and an + * output 'y', the states are, in that order, x(n-1), x(n-2), y(n-1), + * and y(n-2). Both can be initialised with 0. or the last computed + * values, which are updated by this function. + * + * @return the output sample y + */ +extern inline rta_real_t rta_biquad_df1(const rta_real_t x, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states); + +/** + * Biquad computation, using a transposed direct form II. + * + * <pre> + * x + * --------+---------------+---------------+ + * | | | + * |b2 |b1 |b0 + * V V V y + * (+)--->[z-1]--->(+)--->[z-1]--->(+)----+-------> + * ^ ^ | + * |-a2 |-a1 | + * | | | + * +---------------+---------------------+ + * + * </pre> + * + * @param x is an input sample + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param states is a vector of 2 elements: states[0] is the one + * sample delay state and states[1] is the two samples delay + * state. Both can be initialised with 0. or the last computed values, + * which are updated by this function. + * + * @return the output sample y + */ +extern inline rta_real_t rta_biquad_df2t(const rta_real_t x, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states); + +/** + * Biquad computation, using a direct form I. + * + * <pre> + * x b0 y + * --------+----->----->( + )-------->-----+-------> + * | ^ ^ ^ ^ | + * V b1 / / \ \ -a1 V + * [x-1]--->----/ / \ \------<---[y-1] + * | / \ | + * V b2 / \ -a2 V + * [x-2]--->---/ \-----<---[y-2] + * + * </pre> + * + * @param x is an input sample + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param a_stride is 'a' stride + * @param states is a vector of 4 elements: for an input 'x' and an + * output 'y', the states are, in that order, x(n-1), x(n-2), y(n-1), + * and y(n-2). Both can be initialised with 0. or the last computed + * values, which are updated by this function. + * @param s_stride is 'states' strides. + * + * @return the output sample y + */ +extern inline rta_real_t rta_biquad_df1_stride( + const rta_real_t x, + const rta_real_t * b, const int a_stride, + const rta_real_t * a, const int b_stride, + rta_real_t * states, const int s_stride); + +/** + * Biquad computation, using a transposed direct form II. + * + * <pre> + * + * x + * --------+---------------+---------------+ + * | | | + * |b2 |b1 |b0 + * V V V y + * (+)--->[z-1]--->(+)--->[z-1]--->(+)----+-------> + * ^ ^ | + * |-a2 |-a1 | + * | | | + * +---------------+---------------------+ + * + * </pre> + * + * @param x is an input sample + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param a_stride is 'a' stride + * @param states is a vector of 2 elements: states[0] is the one + * sample delay state and states[1] is the two samples delay + * state. Both can be initialised with 0. or the last computed values, + * which are updated by this function. + * @param s_stride is 'states' strides. + * + * @return the output sample y + */ +extern inline rta_real_t rta_biquad_df2t_stride( + const rta_real_t x, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride); + +/** + * Biquad computation on a vector of samples, using a direct form I. + * + * \see rta_biquad_df1 + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_size is the size of 'y' and 'x' + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param states is a vector of 4 elements: for an input 'x' and an + * output 'y', the states are, in that order, x(n-1), x(n-2), y(n-1), + * and y(n-2). Both can be initialised with 0. or the last computed + * values, which are updated by this function. + */ +void rta_biquad_df1_vector(rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states); + +/** + * Biquad computation on a vector of samples, using a transposed + * direct form II. + * + * \see rta_biquad_df2t + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_size is the size of 'y' and 'x' + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param states is a vector of 2 elements: states[0] is the one + * sample delay state and states[1] is the two samples delay + * state. Both can be initialised with 0. or the last computed values, + * which are updated by this function. + */ +void rta_biquad_df2t_vector(rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t * b, const rta_real_t * a, + rta_real_t * states); + +/** + * Biquad computation on a vector of samples, using a direct form I. + * + * \see rta_biquad_df1 + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param y_stride is 'y' stride + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_stride is 'x' stride + * @param x_size is the size of 'y' and 'x' + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param a_stride is 'a' stride + * @param states is a vector of 4 elements: for an input 'x' and an + * output 'y', the states are, in that order, x(n-1), x(n-2), y(n-1), + * and y(n-2). Both can be initialised with 0. or the last computed + * values, which are updated by this function. + * @param s_stride is 'states' strides. + */ +void rta_biquad_df1_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride); + +/** + * Biquad computation on a vector of samples, using a transposed + * direct form II. + * + * \see rta_biquad_df2t + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param y_stride is 'y' stride + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_stride is 'x' stride + * @param x_size is the size of 'y' and 'x' + * @param b is a vector of feed-forward coefficients. b0 is b[0], b1 + * is b[1] and b2 is b[2]. + * @param b_stride is 'b' stride + * @param a is a vector of feed-backward coefficients. Note that a1 is + * a[0] and a2 is a[1] (and a0 is supposed to be 1.). + * @param a_stride is 'a' stride + * @param states is a vector of 2 elements: states[0] is the one + * sample delay state and states[1] is the two samples delay + * state. Both can be initialised with 0. or the last computed values, + * which are updated by this function. + * @param s_stride is 'states' strides. + */ +void rta_biquad_df2t_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t * b, const int b_stride, + const rta_real_t * a, const int a_stride, + rta_real_t * states, const int s_stride); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_BIQUAD_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_correlation.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_correlation.c new file mode 100644 index 0000000000000000000000000000000000000000..bb70f872098acaea3a502ebc0333a54a0e74a64f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_correlation.c @@ -0,0 +1,326 @@ +/** + * @file rta_correlation.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 27 12:25:16 2007 + * + * @brief Correlation (cross or auto) + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_correlation.h" + + +/* specific implementations */ +#if defined(RTA_USE_VECLIB) +//#include <vDSP.h> +#include <Accelerate/Accelerate.h> +#endif + +/* Fast, unbiased by nature, recommended if (c_size / filter_size > 20) */ +/* Requirement: (a_size, b_size) >= c_size + filter_size */ +/* Warning: for VecLib, a_size is required to be aligned on a multiple */ +/* of 4, that is */ +/* a_size >= 'c_size' + 4*(('filter_size'+ 4 - 1)/4) */ +void rta_correlation_fast( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int filter_size) +{ +#if defined(RTA_USE_VECLIB) + if(filter_size <= 2044 && filter_size + c_size >=12) + { +#if (RTA_REAL_TYPE == RTA_FLOAT_TYPE) + vDSP_conv(input_vector_a, 1, input_vector_b, 1, correlation, 1, + c_size, filter_size); +#elif (RTA_REAL_TYPE == RTA_DOUBLE_TYPE) + vDSP_convD(input_vector_a, 1, input_vector_b, 1, correlation, 1, + c_size, filter_size); +#endif + } + else + { +#endif /* RTA_USE_VECLIB */ + +/* Base algorithm */ + int c,f; + for(c=0; c<c_size; c++) + { + correlation[c] = 0.0; + for(f=0; f<filter_size; f++) + { + correlation[c] += input_vector_a[f+c] * input_vector_b[f]; + } + } /* end of base algorithm */ + +#if defined(RTA_USE_VECLIB) + } +#endif + return; +} + +/* Requirement: {a_size*a_stride, b_size*b_stride} >= */ +/* (c_size+filter_size)*c_stride */ +/* Warning: for VecLib, a_size is required to be aligned on a multiple */ +/* of 4, that is */ +/* a_size >= 'c_size' + 4*(('filter_size'+ 4 - 1)/4) */ +void rta_correlation_fast_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int filter_size) +{ +#if defined(RTA_USE_VECLIB) + if(filter_size <= 2044 && filter_size + c_size >=12) + { +#if (RTA_REAL_TYPE == RTA_FLOAT_TYPE) + vDSP_conv(input_vector_a, a_stride, input_vector_b, b_stride, + correlation, c_stride, c_size, filter_size); +#elif (RTA_REAL_TYPE == RTA_DOUBLE_TYPE) + vDSP_convD(input_vector_a, a_stride, input_vector_b, b_stride, + correlation, c_stride, c_size, filter_size); +#endif + } + else + { +#endif /* RTA_USE_VECLIB */ + +/* Base algorithm */ + int c, ca, fa, fb; + for(c=0, ca=0; c<c_size*c_stride; c+=c_stride, ca+=a_stride) + { + correlation[c] = 0.0; + for(fa=0, fb=0; fa<filter_size*a_stride; fa+=a_stride, fb+=b_stride) + { + correlation[c] += + input_vector_a[fa+ca] * input_vector_b[fb]; + } + } /* end of base algorithm */ + +#if defined(RTA_USE_VECLIB) + } +#endif + return; +} + +/* Requirement: (a_size, b_size) >= max_filter_size > c_size */ +void rta_correlation_raw( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int max_filter_size) +{ + int c,f; + for(c=0; c<c_size; c++) + { + correlation[c] = 0.0; + for(f=0; f<max_filter_size-c; f++) + { + correlation[c] += input_vector_a[f+c] * input_vector_b[f]; + } + } + return; +} + +/* Requirement: (a_size, b_size) >= max_filter_size > c_size */ +void rta_correlation_raw_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int max_filter_size) +{ + int c, ca, fa, fb; + for(c=0, ca=0; c<c_size*c_stride; c+=c_stride, ca+=a_stride) + { + correlation[c] = 0.0; + for(fa=0, fb=0; + fa<max_filter_size*a_stride-ca; + fa+=a_stride, fb+=b_stride) + { + correlation[c] += input_vector_a[fa+ca] * input_vector_b[fb]; + } + } + return; +} + + +/* Requirements: (a_size, b_size) >= max_filter_size > c_size */ +void rta_correlation_unbiased( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int max_filter_size) +{ + int c,f; + for(c=0; c<c_size; c++) + { + correlation[c] = 0.0; + for(f=0; f<max_filter_size-c; f++) + { + correlation[c] += input_vector_a[f+c] * input_vector_b[f]; + } + correlation[c] /= f; + } + return; +} + +/* Requirements: (a_size, b_size) >= max_filter_size > c_size */ +void rta_correlation_unbiased_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int max_filter_size) +{ + int c, ca, f, fa, fb; + for(c=0, ca=0; c<c_size*c_stride; c+=c_stride, ca+=a_stride) + { + correlation[c] = 0.0; + for(f=0, fa=0, fb=0; + fa<max_filter_size*a_stride-ca; + f++, fa+=a_stride, fb+=b_stride) + { + correlation[c] += input_vector_a[fa+ca] * input_vector_b[fb]; + } + correlation[c] /= f; + } + + return; +} + + +rta_real_t rta_correlation_fast_normalization_factor(const unsigned int filter_size) +{ + rta_real_t normalization = 1.; + + if(filter_size>0) + { + normalization = 1. / (rta_real_t)filter_size; + } + return normalization; +} + +rta_real_t rta_correlation_raw_normalization_factor(const unsigned int max_filter_size) +{ + rta_real_t normalization = 1.; + + if(max_filter_size>0) + { + normalization = 1. / (rta_real_t)(max_filter_size + 1); + } + return normalization; +} + + +/* Requirement: (a_size, b_size) >= c_size + filter_size */ +void rta_correlation_fast_scaled( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int filter_size, const rta_real_t scale) +{ + int c,f; + for(c=0; c<c_size; c++) + { + correlation[c] = 0.0; + for(f=0; f<filter_size; f++) + { + correlation[c] += input_vector_a[f+c] * input_vector_b[f]; + } + correlation[c] *= scale; + } + return; +} + + +/* Requirement: {a_size*a_stride, b_size*b_stride} >= (c_size+filter_size)*c_stride */ +void rta_correlation_fast_scaled_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int filter_size, const rta_real_t scale) +{ + int c,ca,fa,fb; + for(c=0, ca=0; c<c_size*c_stride; c+=c_stride, ca+=a_stride) + { + correlation[c] = 0.0; + for(fa=0, fb=0; fa<filter_size*a_stride; fa+=a_stride, fb+=b_stride) + { + correlation[c] += + input_vector_a[fa+ca] * input_vector_b[fb]; + } + correlation[c] *= scale; + } + return; +} + +/* Requirement: (a_size, b_size) >= max_filter_size */ +void rta_correlation_raw_scaled( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int max_filter_size, const rta_real_t scale) +{ + int c,f; + for(c=0; c<c_size; c++) + { + correlation[c] = 0.0; + for(f=0; f<max_filter_size-c; f++) + { + correlation[c] += input_vector_a[f+c] * input_vector_b[f]; + } + correlation[c] *= scale; + } + return; +} + +/* Requirement: (a_size, b_size) >= max_filter_size */ +void rta_correlation_raw_scaled_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int max_filter_size, const rta_real_t scale) +{ + int c, ca, fa, fb; + for(c=0, ca=0; c<c_size*c_stride; c+=c_stride, ca+=a_stride) + { + correlation[c] = 0.0; + for(fa=0, fb=0; + fa<max_filter_size*a_stride-ca; + fa+=a_stride, fb+=b_stride) + { + correlation[c] += input_vector_a[fa+ca] * input_vector_b[fb]; + } + correlation[c] *= scale; + } + return; +} + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_correlation.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_correlation.h new file mode 100644 index 0000000000000000000000000000000000000000..b0cf8b13cb0b53f4e50d5d27e670abc11bd2e61a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_correlation.h @@ -0,0 +1,372 @@ +/** + * @file rta_correlation.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 27 12:25:16 2007 + * + * @brief Correlation (cross or auto) + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_CORRELATION_H_ +#define _RTA_CORRELATION_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = \sum_{f=0}^{filter\_size-1} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is unbiased by nature but misses some information, + * specially for the first coefficients. It should be negligible if + * 'filter_size' is much greater than 'c_size', like ('filter_size' / + * 'c_size' > 20). + * + * @param correlation size is 'c_size' + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'c_size' + 'filter_size' + * @param input_vector_b size b_size must be >= 'c_size' + * @param filter_size is the maximum shift for 'input_vector_a'. In + * practice, 'filter_size' == (a_size - 'c_size') + */ +void +rta_correlation_fast( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int filter_size); + + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = \sum_{f=0}^{filter\_size-1} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * + * This function is unbiased by nature but misses some information, + * specially for the first coefficients. It should be negligible if + * 'filter_size' is much greater than 'c_size', like ('filter_size' / + * 'c_size' > 20). + * + * @param correlation size is 'c_size' + * @param c_stride is 'correlation' stride + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size must be >= 'c_size' + 'filter_size' + * @param a_stride is 'input_vector_a' stride + * @param input_vector_b size must be >= 'c_size' + * @param b_stride is 'input_vector_b' stride + * @param filter_size is the maximum shift for 'input_vector_a'. In + * practice, 'filter_size' == (a_size - 'c_size') + */ +void +rta_correlation_fast_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int filter_size); + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = \sum_{f=0}^{max\_filter\_size-i} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is biased but uses all the information available for + * each coefficient. + * + * @param correlation size is 'c_size' + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'max_filter_size' + * @param input_vector_b size b_size must be >= 'max_filter_size' + * @param max_filter_size is the maximum shift for 'input_vector_a'. + * 'max_filter_size' must be > 'c_size'. + * In practice, 'max_filter_size' == a_size + */ +void +rta_correlation_raw( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int max_filter_size); + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = \sum_{f=0}^{max\_filter\_size-i} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is biased but uses all the information available for + * each coefficient. + * + * @param correlation size is 'c_size' + * @param c_stride is 'correlation' stride + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'max_filter_size' + * @param a_stride is 'input_vector_a' stride + * @param input_vector_b size b_size must be >= 'max_filter_size' + * @param b_stride is 'input_vector_b' stride + * @param max_filter_size is the maximum shift for 'input_vector_a'. + * 'max_filter_size' must be > 'c_size'. + * In practice, 'max_filter_size' == a_size + */ +void +rta_correlation_raw_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int max_filter_size); + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = \frac{1}{max\_filter\_size-i} \sum_{f=0}^{max\_filter\_size-i} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is unbiased as it normalizes each coefficient by its + * actual filter size. + * + * @param correlation size is 'c_size' + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'max_filter_size' + * @param input_vector_b size b_size must be >= 'max_filter_size' + * @param max_filter_size is the maximum shift for 'input_vector_a'. + * 'max_filter_size' must be > 'c_size'. + * In practice, 'max_filter_size' == a_size + */ +void +rta_correlation_unbiased( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int max_filter_size); + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = \frac{1}{max\_filter\_size-i} \sum_{f=0}^{max\_filter\_size-i} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is unbiased as it normalizes each coefficient by its + * actual filter size. + * + * @param correlation size is 'c_size' + * @param c_stride is 'correlation' stride + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'max_filter_size' + * @param a_stride is 'input_vector_a' stride + * @param input_vector_b size b_size must be >= 'max_filter_size' + * @param b_stride is 'input_vector_b' stride + * @param max_filter_size is the maximum shift for 'input_vector_a'. + * 'max_filter_size' must be > 'c_size'. + * In practice, 'max_filter_size' == a_size + */ +void +rta_correlation_unbiased_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int max_filter_size); + +/** + * Generate a factor '*normalization' to multiply the correlation + * with, in order to normalize the correlation_fast values against the + * 'max_filter_size'. + * + * @param filter_size is the maximum shift for 'input_vector_a' + * + * @return normalization factor to multiply the correlation_fast with + * + * \see rta_correlation_fast_scaled + * \see rta_correlation_fast_scaled_stride + */ +rta_real_t +rta_correlation_fast_normalization_factor(const unsigned int filter_size); + +/** + * Generate a factor '*normalization' to multiply the correlation + * with, in order to normalize the correlation_raw values against the + * 'max_filter_size'. + * + * @param max_filter_size is the maximum shift for 'input_vector_a' + * + * @return normalization factor to multiply the correlation_raw with + * + * \see rta_correlation_raw_scaled + * \see rta_correlation_raw_scaled_stride + */ +rta_real_t +rta_correlation_raw_normalization_factor(const unsigned int max_filter_size); + + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = scale \sum_{f=0}^{filter\_size-1} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is unbiased by nature but misses some information, + * specially for the first coefficients. It should be negligible if + * 'filter_size' is much greater than 'c_size', like ('filter_size' / + * 'c_size' > 20). + * + * @param correlation size is 'c_size' + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size must be >= 'c_size' + 'filter_size' + * @param input_vector_b size must be >= 'c_size' + * @param filter_size is the maximum shift for 'input_vector_a'. In + * practice, 'filter_size' == (a_size - 'c_size') + * @param scale is a factor to multiply the 'correlation' values with + */ +void +rta_correlation_fast_scaled( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int filter_size, const rta_real_t scale); + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$(i) = scale \sum_{f=0}^{filter\_size-1} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is unbiased by nature but misses some information, + * specially for the first coefficients. It should be negligible if + * 'filter_size' is much greater than 'c_size', like ('filter_size' / + * 'c_size' > 20). + * + * @param correlation size is 'c_size' + * @param c_stride is 'correlation' stride + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size must be >= 'c_size' + 'filter_size' + * @param a_stride is 'input_vector_a' stride + * @param input_vector_b size must be >= 'c_size' + * @param b_stride is 'input_vector_b' stride + * @param filter_size is the maximum shift for 'input_vector_a'. In + * practice, 'filter_size' == (a_size - 'c_size') + * @param scale is a factor to multiply the 'correlation' values with + */ +void +rta_correlation_fast_scaled_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int filter_size, const rta_real_t scale); + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = scale \sum_{f=0}^{max\_filter\_size-i} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is biased but uses all the information available for + * each coefficient. + * + * @param correlation size is 'c_size' + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'max_filter_size' + * @param input_vector_b size b_size must be >= 'max_filter_size' + * @param max_filter_size is the maximum shift for 'input_vector_a'. + * 'max_filter_size' must be > 'c_size'. + * In practice, 'max_filter_size' == a_size + * @param scale is a factor to multiply the 'correlation' values with + */ +void +rta_correlation_raw_scaled( + rta_real_t * correlation, const unsigned int c_size, + const rta_real_t * input_vector_a, + const rta_real_t * input_vector_b, + const unsigned int max_filter_size, const rta_real_t scale); + + +/** + * Compute correlation between 'input_vector_a' and 'input_vector_b' into + * 'correlation'. If 'input_vector_a' == 'input_vector_b', it computes + * auto-correlation. This function can run in place if 'correlation' == + * 'input_vector_a' or 'correlation' == 'input_vector_b'. + * + * \f$C(i) = scale \sum_{f=0}^{max\_filter\_size-i} A(f+i) \cdot B(f), i=\{0,c\_size-1\}\f$ + * + * This function is biased but uses all the information available for + * each coefficient. + * + * @param correlation size is 'c_size' + * @param c_stride is 'correlation' stride + * @param c_size is the 'correlation' order + 1, 'c_size' must be > 0 + * @param input_vector_a size a_size must be >= 'max_filter_size' + * @param a_stride is 'input_vector_a' stride + * @param input_vector_b size b_size must be >= 'max_filter_size' + * @param b_stride is 'input_vector_b' stride + * @param max_filter_size is the maximum shift for 'input_vector_a'. + * 'max_filter_size' must be > 'c_size'. + * In practice, 'max_filter_size' == a_size + * @param scale is a factor to multiply the 'correlation' values with + */ +void +rta_correlation_raw_scaled_stride( + rta_real_t * correlation, const int c_stride, const unsigned int c_size, + const rta_real_t * input_vector_a, const int a_stride, + const rta_real_t * input_vector_b, const int b_stride, + const unsigned int max_filter_size, const rta_real_t scale); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_CORRELATION_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_cubic.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_cubic.c new file mode 100644 index 0000000000000000000000000000000000000000..8ea410ee11e281506d951779a39849f4cc5a2c06 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_cubic.c @@ -0,0 +1,58 @@ +/** + * @file rta_cubic.h + * @author Norbert.Schnell@ircam.fr + * + * @copyright + * Copyright (C) 1994, 1995, 1998, 1999, 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* coefficient atable for cubic interpolation */ + +#include "rta_cubic.h" + +static rta_cubic_coefs_t _rta_cubic_table[RTA_CUBIC_TABLE_SIZE]; +rta_cubic_coefs_t *rta_cubic_table = _rta_cubic_table; + +void rta_cubic_table_init () +{ + int i; + float f; + rta_cubic_coefs_t *p = rta_cubic_table; + + for (i = 0; i < RTA_CUBIC_TABLE_SIZE; i++) + { + f = i * (1.0 / RTA_CUBIC_TABLE_SIZE); + p->pm1 = -0.1666667 * f * (1 - f) * (2 - f); + p->p0 = 0.5 * (1 + f) * (1 - f) * (2 - f); + p->p1 = 0.5 * (1 + f) * f * (2 - f); + p->p2 = -0.1666667 * (1 + f) * f * (1 - f); + p++; + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_cubic.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_cubic.h new file mode 100644 index 0000000000000000000000000000000000000000..1da3d0d2b5e4a77540448b07b4ea8821892a13fd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_cubic.h @@ -0,0 +1,149 @@ +/** + * @file rta_cubic.h + * @author Norbert.Schnell@ircam.fr + * + * @copyright + * Copyright (C) 1994, 1995, 1998, 1999, 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_CUBIC_H +#define _RTA_CUBIC_H + + +/******************************************************************************* + * + * cubic interpolation + * + */ + +#ifndef RTA_CUBIC_TABLE_SIZE +#define RTA_CUBIC_TABLE_SIZE 256 +#endif + +#define RTA_CUBIC_HEAD 1 +#define RTA_CUBIC_TAIL 2 + +#define RTA_CUBIC_TABLE_BITS 8 +#define RTA_CUBIC_TABLE_SIZE 256 + +#define RTA_CUBIC_INTPHASE_LOST_BITS 8 +#define RTA_CUBIC_INTPHASE_FRAC_BITS (RTA_CUBIC_TABLE_BITS + RTA_CUBIC_INTPHASE_LOST_BITS) +#define RTA_CUBIC_INTPHASE_FRAC_SIZE (1 << RTA_CUBIC_INTPHASE_FRAC_BITS) + +#define rta_cubic_get_table_index_from_idefix(i) \ + ((int)(((i).frac & RTA_CUBIC_IDEFIX_BIT_MASK) >> RTA_CUBIC_IDEFIX_SHIFT_BITS)) + +#define rta_cubic_get_table_index_from_frac(f) \ + ((unsigned int)((f) * (double)RTA_CUBIC_TABLE_SIZE) & (RTA_CUBIC_TABLE_SIZE - 1)) + +#define RTA_CUBIC_IDEFIX_SHIFT_BITS 24 +#define RTA_CUBIC_IDEFIX_BIT_MASK 0xff000000 + +#define rta_cubic_intphase_scale(f) ((f) * RTA_CUBIC_INTPHASE_FRAC_SIZE) +#define rta_cubic_intphase_get_int(i) ((i) >> RTA_CUBIC_INTPHASE_FRAC_BITS) +#define rta_cubic_intphase_get_frac(i) ((i) & (RTA_CUBIC_INTPHASE_FRAC_SIZE - 1)) + +typedef struct +{ + float pm1; + float p0; + float p1; + float p2; +} rta_cubic_coefs_t; + +rta_cubic_coefs_t *rta_cubic_table; + +void rta_cubic_table_init (); + +#define rta_cubic_get_coefs(f) \ + (rta_cubic_table + rta_cubic_get_table_index_from_frac(f)) + +#define rta_cubic_calc(x, p) \ + ((x)[-1] * (p)->pm1 + (x)[0] * (p)->p0 + (x)[1] * (p)->p1 + (x)[2] * (p)->p2) + +#define rta_cubic_calc_stride(x, p, s) \ + ((x)[-(s)] * (p)->pm1 + (x)[0] * (p)->p0 + (x)[s] * (p)->p1 + (x)[2 * (s)] * (p)->p2) + +#define rta_cubic_calc_head(x, p) \ + ((x)[0] * (p)->p0 + (x)[1] * (p)->p1 + (x)[2] * (p)->p2) + +#define rta_cubic_calc_stride_head(x, p, s) \ +((x)[0] * (p)->p0 + (x)[s] * (p)->p1 + (x)[2 * (s)] * (p)->p2) + +#define rta_cubic_calc_tailm2(x, p) \ + ((x)[-1] * (p)->pm1 + (x)[0] * (p)->p0 + (x)[1] * (p)->p1) + +#define rta_cubic_calc_tailm2_xm1(x, p, xm1) \ + ((x)[-1] * (p)->pm1 + (x)[0] * (p)->p0 + (x)[1] * (p)->p1 + (xm1) * (p)->p2) + +#define rta_cubic_calc_stride_tailm2(x, p, s) \ + ((x)[-(s)] * (p)->pm1 + (x)[0] * (p)->p0 + (x)[s] * (p)->p1) + +#define rta_cubic_calc_stride_tailm2_xm1(x, p, s, xm1) \ + ((x)[-(s)] * (p)->pm1 + (x)[0] * (p)->p0 + (x)[s] * (p)->p1 + (xm1) * (p)->p2) + +#define rta_cubic_calc_tailm1(x, p) \ + ((x)[-1] * (p)->pm1 + (x)[0] * (p)->p0) + +#define rta_cubic_calc_tailm1_xm2_xm1(x, p, xm2, xm1) \ + ((x)[-1] * (p)->pm1 + (x)[0] * (p)->p0 + (xm2) * (p)->p1 + (xm1) * (p)->p2) + +#define rta_cubic_calc_stride_tailm1(x, p, s) \ + ((x)[-(s)] * (p)->pm1 + (x)[0] * (p)->p0) + +#define rta_cubic_calc_stride_tailm1_xm2_xm1(x, p, s, xm2, xm1) \ + ((x)[-(s)] * (p)->pm1 + (x)[0] * (p)->p0 + (xm2) * (p)->p1 + (xm1) * (p)->p2) + +#define rta_cubic_idefix_interpolate(p, i, y) \ +do { \ + rta_cubic_coefs_t *ft = rta_cubic_table + rta_cubic_get_table_index_from_idefix(i); \ + *(y) = rta_cubic_calc((p) + (i).index, ft); \ + } while(0) + +#define rta_cubic_idefix_interpolate_stride(p, i, s, y) \ + do { \ + rta_cubic_coefs_t *ft = rta_cubic_table + rta_cubic_get_table_index_from_idefix(i); \ + *(y) = rta_cubic_calc_stride((p) + (s) * (i).index, ft, (s)); \ + } while(0) + +#define rta_cubic_intphase_interpolate(p, i, y) \ + do { \ + float* q = (p) + ((i) >> RTA_CUBIC_INTPHASE_FRAC_BITS); \ + rta_cubic_coefs_t *ft = rta_cubic_table + (((i) >> RTA_CUBIC_INTPHASE_LOST_BITS) & (RTA_CUBIC_TABLE_SIZE - 1)); \ + *(y) = rta_cubic_calc(q, ft); \ + } while(0) + +#define rta_cubic_interpolate(p, i, f, y) \ + do { \ + rta_cubic_coefs_t *ft = rta_cubic_table + rta_cubic_get_table_index_from_frac(f); \ + *(y) = rta_cubic_calc((p) + (i), ft); \ + } while(0) + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_dct.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_dct.c new file mode 100644 index 0000000000000000000000000000000000000000..c0c15cff772a00fa02b5ec409e61e4c849a149f3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_dct.c @@ -0,0 +1,320 @@ +/** + * @file rta_dct.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Discrete Cosine Transform (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * See http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_dct.h" +#include "rta_math.h" + +int rta_dct_weights(rta_real_t * weights_matrix, + const unsigned int input_size, + const unsigned int dct_order, + const rta_dct_t dct_t) +{ + int i,j; + int ret = 1; /* return value */ + + /* This is the orthogonal one, the one you want */ + if(dct_t == rta_dct_slaney || dct_t == rta_dct_htk) + { + for(i=0; i<dct_order; i++) + { + for(j=0; j<input_size; j++) + { + weights_matrix[i*input_size+j] = + rta_cos(i*((j+1)*2.-1.)/(2.*input_size)*M_PI) * + rta_sqrt(2./input_size); + } + } + + /* Make it unitary (but not for HTK) */ + if(dct_t == rta_dct_slaney) + { + /* first line only */ + for(j=0; j<input_size; j++) + { + weights_matrix[j] /= M_SQRT2; + } + } + } + + /* + * type 1 (PLPDCT) with implicit repeating of first, last bins + * Deep in the heart of the rasta/feacalc code, there is the logic + * that the first and last auditory bands extend beyond the edge of + * the actual spectra, and they are thus copied from their neighbors. + * Normally, we just ignore those bands and take the 19 in the middle, + * but when feacalc calculates mfccs, it actually takes the dct + * over the spectrum *including* the repeated bins at each end. + * Here, we simulate 'repeating' the bins and an nrow+2-length + * spectrum by adding in extra DCT weight to the first and last + * bins. + */ + else if(dct_t == rta_dct_feacalc) + { + for(i=0; i<dct_order; i++) + { + for(j=0; j<input_size; j++) + { + weights_matrix[i*input_size+j] = + rta_cos(i*(j+1.)/(input_size+1.)*M_PI) * 2.; + } + + /* Add in edge points at ends (includes fixup scale) */ + weights_matrix[i*input_size] += 1.; + if(i&1) /* odd */ + { + weights_matrix[(i+1)*input_size-1] -= 1.; + } + else /* even */ + { + weights_matrix[(i+1)*input_size-1] += 1.; + } + } + + for(i=0; i<dct_order*input_size; i++) + { + weights_matrix[i] /= 2.*(input_size+1.); + } + } + + /* dpwe type 1 - same as old spec2cep that expanded & used fft */ + else if(dct_t == rta_dct_plp) + { + for(i=0; i<dct_order; i++) + { + for(j=0; j<input_size; j++) + { + weights_matrix[i*input_size+j] = + rta_cos(i*j/(input_size-1.)*M_PI) / (input_size-1.); + + } + /* Fixup 'non-repeated' points */ + weights_matrix[i*input_size] *= 0.5; + weights_matrix[(i+1)*input_size-1] *= 0.5; + } + } + else + { + ret = 0; + } + + return ret; +} + +int rta_dct_weights_stride(rta_real_t * weights_matrix, const int w_stride, + const unsigned int input_size, + const unsigned int dct_order, + const rta_dct_t dct_t) +{ + int i,j; + int ret = 1; /* return value */ + + /* This is the orthogonal one, the one you want */ + if(dct_t == rta_dct_slaney || dct_t == rta_dct_htk) + { + for(i=0; i<dct_order; i++) + { + for(j=0; j<input_size; j++) + { + weights_matrix[(i*input_size+j)*w_stride] = + rta_cos(i*((j+1)*2.-1.)/(2.*input_size)*M_PI) * + rta_sqrt(2./input_size); + } + } + + /* Make it unitary (but not for HTK) */ + if(dct_t == rta_dct_slaney) + { + /* first line only */ + for(j=0; j<input_size; j++) + { + weights_matrix[j*w_stride] /= M_SQRT2; + } + } + } + + /* + * type 1 (PLPDCT) with implicit repeating of first, last bins + * Deep in the heart of the rasta/feacalc code, there is the logic + * that the first and last auditory bands extend beyond the edge of + * the actual spectra, and they are thus copied from their neighbors. + * Normally, we just ignore those bands and take the 19 in the middle, + * but when feacalc calculates mfccs, it actually takes the dct + * over the spectrum *including* the repeated bins at each end. + * Here, we simulate 'repeating' the bins and an nrow+2-length + * spectrum by adding in extra DCT weight to the first and last + * bins. + */ + else if(dct_t == rta_dct_feacalc) + { + for(i=0; i<dct_order; i++) + { + for(j=0; j<input_size; j++) + { + weights_matrix[(i*input_size+j)*w_stride] = + rta_cos(i*(j+1.)/(input_size+1.)*M_PI) * 2.; + } + + /* Add in edge points at ends (includes fixup scale) */ + weights_matrix[i*input_size*w_stride] += 1.; + if(i&1) /* odd */ + { + weights_matrix[((i+1)*input_size-1)*w_stride] -= 1.; + } + else /* even */ + { + weights_matrix[((i+1)*input_size-1)*w_stride] += 1.; + } + } + + for(i=0; i<dct_order*input_size; i++) + { + weights_matrix[i*w_stride] /= 2.*(input_size+1.); + } + } + + /* dpwe type 1 - same as old spec2cep that expanded & used fft */ + else if(dct_t == rta_dct_plp) + { + for(i=0; i<dct_order; i++) + { + for(j=0; j<input_size; j++) + { + weights_matrix[(i*input_size+j)*w_stride] = + rta_cos(i*j/(input_size-1.)*M_PI) / (input_size-1.); + + } + /* Fixup 'non-repeated' points */ + weights_matrix[i*input_size*w_stride] *= 0.5; + weights_matrix[((i+1)*input_size-1)*w_stride] *= 0.5; + } + } + else + { + ret = 0; + } + + return ret; +} + +/* Calculate dct from spectral samples */ +void rta_dct(rta_real_t * dct, const rta_real_t * input_vector, + const rta_real_t * weights_matrix, + const unsigned int input_size, + const unsigned int dct_order) +{ + unsigned int i,j; + + for(i=0; i<dct_order; i++) + { + dct[i] = 0.; + for(j=0; j<input_size; j++) + { + dct[i] += weights_matrix[i*input_size+j] * input_vector[j]; + } + } + + return; +} + +void rta_dct_scaled(rta_real_t * dct, const rta_real_t * input_vector, + const rta_real_t * weights_matrix, + const unsigned int input_size, + const unsigned int dct_order, + rta_real_t scale) +{ + unsigned int i,j; + + for(i=0; i<dct_order; i++) + { + dct[i] = 0.; + for(j=0; j<input_size; j++) + { + dct[i] += weights_matrix[i*input_size+j] * input_vector[j] * scale; + } + } + + return; +} + +/* Calculate dct from spectral samples */ +void rta_dct_stride(rta_real_t * dct, const int d_stride, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_matrix, const int w_stride, + const unsigned int input_size, + const unsigned int dct_order) +{ + unsigned int i,j; + + for(i=0; i<dct_order; i++) + { + dct[i*d_stride] = 0.; + for(j=0; j<input_size; j++) + { + dct[i*d_stride] += weights_matrix[(i*input_size+j)*w_stride] * + input_vector[j*i_stride]; + } + } + + return; +} + +/* Calculate dct from spectral samples */ +void rta_dct_stride_scaled(rta_real_t * dct, const int d_stride, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_matrix, const int w_stride, + const unsigned int input_size, + const unsigned int dct_order, + rta_real_t scale) +{ + unsigned int i,j; + + for(i=0; i<dct_order; i++) + { + dct[i*d_stride] = 0.; + for(j=0; j<input_size; j++) + { + dct[i*d_stride] += weights_matrix[(i*input_size+j)*w_stride] * + input_vector[j*i_stride] * scale; + } + } + + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_dct.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_dct.h new file mode 100644 index 0000000000000000000000000000000000000000..7299270e85282143b5f9874a3b7523304bde4f07 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_dct.h @@ -0,0 +1,188 @@ +/** + * @file rta_dct.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Discrete Cosine Transform (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * See http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_DCT_H_ +#define _RTA_DCT_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + rta_dct_plp = 1, /**< dpwe type 1 - same as old spec2cep that expanded & used fft */ + rta_dct_slaney = 2, /**< orthogonal and unitary (Auditory Toolbox like) */ + rta_dct_htk = 3, /**< orthogonal but not unitary (HTK like) */ + rta_dct_feacalc = 4 /**< type 1 with implicit repeating of first, last bins */ +} rta_dct_t; + + +/* from spec2cep.m */ + +/** + * Generate a matrix of weights 'weights_matrix' to perform a discrete + * cosine transform. This is type II dct, or type I if type is + * specified as 'PLPDCT'. + * + * @param weights_matrix size is 'input_size'*'dct_order' + * @param input_size number of input mel bands + * @param dct_order number of output dct coefficients + * @param dct_type + * PLPDCT dpwe type 1: same as old spec2cep that expanded & used fft + * slaney_dct: orthogonal and unitary + * HTKDCT: orthogonal but not unitary (HTK like) + * feacalc_dct: PLPDCT with implicit repeating of first, last bins + * Deep in the heart of the rasta/feacalc code, there is the logic + * that the first and last auditory bands extend beyond the edge of + * the actual spectra, and they are thus copied from their neighbors. + * Normally, we just ignore those bands and take the 19 in the middle, + * but when feacalc calculates mfccs, it actually takes the cepstrum + * over the spectrum *including* the repeated bins at each end. Here, + * we simulate 'repeating' the bins and an nrow+2-length spectrum by + * adding in extra DCT weight to the first and last bins. + * + * @return 1 on success 0 on fail + */ +int rta_dct_weights(rta_real_t * weights_matrix, + const unsigned int input_size, + const unsigned int dct_order, + const rta_dct_t dct_type); + +/** + * Generate a matrix of weights 'weights_matrix' to perform a discrete + * cosine transform. This is type II dct, or type I if type is + * specified as 'PLPDCT'. + * + * @param weights_matrix size is 'input_size'*'dct_order' + * @param w_stride is 'weights_matrix' stride + * @param input_size number of input mel bands + * @param dct_order number of output dct coefficients + * @param dct_type + * PLPDCT dpwe type 1: same as old spec2cep that expanded & used fft + * slaney_dct: orthogonal and unitary + * HTKDCT: orthogonal but not unitary (HTK like) + * feacalc_dct: PLPDCT with implicit repeating of first, last bins + * Deep in the heart of the rasta/feacalc code, there is the logic + * that the first and last auditory bands extend beyond the edge of + * the actual spectra, and they are thus copied from their neighbors. + * Normally, we just ignore those bands and take the 19 in the middle, + * but when feacalc calculates mfccs, it actually takes the cepstrum + * over the spectrum *including* the repeated bins at each end. Here, + * we simulate 'repeating' the bins and an nrow+2-length spectrum by + * adding in extra DCT weight to the first and last bins. + * + * @return 1 on success 0 on fail + */ +int rta_dct_weights_stride(rta_real_t * weights_matrix, const int w_stride, + const unsigned int input_size, + const unsigned int dct_order, + const rta_dct_t dct_type); + +/** + * Perform a discrete cosine transform as + * 'dct' = 'weights_matrix'*'input_vector' + * + * Calculate 'dct' from the log of the spectral samples + * 'input_vector' as + * 'dct' = 'weights_matrix'*log('input_vector') + * to get MFCC. + * + * @param dct size is 'dct_order' + * @param input_vector size is 'input_size' it is actually the log of the + * mel bands + * @param weights_matrix size is 'input_size'*'dct_order' + * @param input_size number of input mel bands + * @param dct_order number of output dct coefficients + * + */ +void rta_dct(rta_real_t * dct, const rta_real_t * input_vector, + const rta_real_t * weights_matrix, + const unsigned int input_size, + const unsigned int dct_order); + +void rta_dct_scaled(rta_real_t * dct, const rta_real_t * input_vector, + const rta_real_t * weights_matrix, + const unsigned int input_size, + const unsigned int dct_order, + rta_real_t scale); + + /** + * + * Perform a discrete cosine transform as + * 'dct' = 'weights_matrix'*'input_vector' + * + * Calculate 'dct' from the log of the spectral samples + * 'input_vector' as + * 'dct' = 'weights_matrix'*log('input_vector') + * to get MFCC. + * + * @param dct size is 'dct_order' + * @param d_stride is 'dct' stride + * @param input_vector size is 'input_size' it is actually the log of the + * mel bands + * @param i_stride is 'input_vector' stride + * @param weights_matrix size is 'input_size'*'dct_order' + * @param w_stride is 'weights_matrix' stride + * @param input_size number of input mel bands + * @param dct_order number of output dct coefficients + * + */ +void rta_dct_stride(rta_real_t * dct, const int d_stride, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_matrix, const int w_stride, + const unsigned int input_size, + const unsigned int dct_order); + +void rta_dct_stride_scaled(rta_real_t * dct, const int d_stride, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_matrix, const int w_stride, + const unsigned int input_size, + const unsigned int dct_order, + rta_real_t scale); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_DCT_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_delta.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_delta.c new file mode 100644 index 0000000000000000000000000000000000000000..3c62bc82f9dc096056fc93e8af67ebac061c3623 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_delta.c @@ -0,0 +1,193 @@ +/** + * @file rta_delta.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Thu Aug 2 18:39:26 2007 + * + * @brief Delta (derivative for a sequence at a fixed sampling rate) + * + * Simple linear slope. Each column (a scalar value during time) is + * filtered separately. + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_delta.h" +#include "rta_math.h" + +/* <filter_size> should be odd and positive */ +int rta_delta_weights(rta_real_t * weights_vector, const unsigned int filter_size) +{ + int i; + rta_real_t filter_value; + + const rta_real_t half_filter_size = rta_floor(filter_size * 0.5); + + for(i=0, filter_value=-half_filter_size; + i<filter_size; + i++, filter_value+=1.) + { + weights_vector[i] = filter_value; + } + + return 1; +} + +/* <filter_size> should be odd and positive */ +int rta_delta_weights_stride(rta_real_t * weights_vector, const int w_stride, + const unsigned int filter_size) +{ + int i; + rta_real_t filter_value; + + const rta_real_t half_filter_size = rta_floor(filter_size * 0.5); + + for(i=0, filter_value=-half_filter_size; + i<filter_size*w_stride; + i+=w_stride, filter_value+=1.) + { + weights_vector[i] = filter_value; + } + + return 1; +} + + +rta_real_t rta_delta_normalization_factor(const unsigned int filter_size) +{ + rta_real_t normalization = 0.; + + if(filter_size>0) + { + int i; + const int half_filter_size = filter_size / 2; + + for(i=1; i<=half_filter_size; i++) + { + normalization += (rta_real_t) (i*i); + } + + normalization = 0.5 / normalization; + } + return normalization; +} + +void rta_delta(rta_real_t * delta, const rta_real_t * input_vector, + const rta_real_t * weights_vector, + const unsigned int filter_size) +{ + unsigned int i; + + *delta = 0.; + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i] != 0.) + { + *delta += input_vector[i] * weights_vector[i]; + } + } + + return; +} + +void rta_delta_stride(rta_real_t * delta, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int filter_size) +{ + unsigned int i; + + *delta = 0.; + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i*w_stride] != 0.) + { + *delta += input_vector[i*i_stride] * weights_vector[i*w_stride]; + } + } + + return; +} + + +void rta_delta_vector(rta_real_t * delta, + const rta_real_t * input_matrix, const unsigned int input_size, + const rta_real_t * weights_vector, const unsigned int filter_size) +{ + unsigned int i,j; + + for(j=0; j<input_size; j++) + { + delta[j] = 0.; + } + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i] != 0.) /* skip zeros */ + { + for(j=0; j<input_size; j++) + { + delta[j] += input_matrix[i*input_size+j] * weights_vector[i]; + } + } + } + + return; +} + +void rta_delta_vector_stride(rta_real_t * delta, const int d_stride, + const rta_real_t * input_matrix, const int i_stride, + const unsigned int input_size, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int filter_size) +{ + int i,j; + + for(j=0; j<input_size*d_stride; j+=d_stride) + { + delta[j] = 0.; + } + + for(i=0; i<filter_size; i++) + { + if(weights_vector[i*w_stride] != 0.) /* skip zeros */ + { + for(j=0; j<input_size; j++) + { + delta[j*d_stride] += input_matrix[(i*input_size+j)*i_stride] * + weights_vector[i*w_stride]; + } + } + } + + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_delta.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_delta.h new file mode 100644 index 0000000000000000000000000000000000000000..7c82c64831088862475e7aefd605eee304102ac3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_delta.h @@ -0,0 +1,209 @@ +/** + * @file rta_delta.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Delta (derivative for a sequence at a fixed sampling rate) + * + * Simple linear slope. Each column (a scalar value during time) is + * filtered separately. + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_DELTA_H_ +#define _RTA_DELTA_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* from deltas.m */ +/** + * + * Generate a vector of weights 'weights_vector' to calculate the + * delta (derivative) of a sequence of regularly sampled values. Use + * a 'filter_size'-points window. to calculate delta using a simple + * linear slope. This mirrors the delta calculation performed in + * feacalc etc. Delta corresponds to the mid-points values (which are + * not used, by the way). + * + * 'filter_size' must be odd and stricly positive. + * + * 'filter_size' == 7 is a common value to calculate the delta-mfcc + * and 'filter_size' == 5 is a common value for delta-delta-mfcc. + * + * Note for HTK 'DELTAWINDOW' (same for 'ACCWINDOW'): + * 'filter_size' == ('DELTAWINDOW' * 2) + 1 + * + * @param weights_vector size is 'filter_size' + * @param filter_size must be odd and stricly positive. + * + * @return 1 on success 0 on fail + */ +int rta_delta_weights(rta_real_t * weights_vector, const unsigned int filter_size); + +/** + * + * Generate a vector of weights 'weights_vector' to calculate the + * delta (derivatives) of a sequence of regularly sampled values. Use + * a 'filter_size'-points window. to calculate delta using a simple + * linear slope. This mirrors the delta calculation performed in + * feacalc etc. Delta corresponds to the mid-points values (which are + * not used, by the way). + * + * 'filter_size' must be odd and stricly positive. + * + * 'filter_size' == 7 is a common value to calculate the delta-mfcc + * and 'filter_size' == 5 is a common value for delta-delta-mfcc. + * + * Note for HTK 'DELTAWINDOW' (same for 'ACCWINDOW'): + * 'filter_size' == ('DELTAWINDOW' * 2) + 1 + * + * @param weights_vector size is 'filter_size' + * @param w_stride is 'weights_vector' stride + * @param filter_size must be odd and stricly positive. + * + * @return 1 on success 0 on fail + */ +int rta_delta_weights_stride(rta_real_t * weights_vector, const int w_stride, + const unsigned int filter_size); + +/** + * Generate a factor to multiply the delta with, in order to normalize + * the 'delta' values against the 'filter_size'. The delta is then the + * slope of the linear regression. Note that it is equivalent to + * multiply the 'weights_vector' values (but it is less precise, as + * errors in weights are added). + * + * \f$normalization = \frac{1}{2 \left(\sum\limits_{\theta=1}^{\theta=filter_size} \theta^2 \right)}\f$ + * + * @param filter_size is the number of points to evaluate the delta + * + * @return normalization factor to multiply the delta with + */ +rta_real_t rta_delta_normalization_factor(const unsigned int filter_size); + +/** + * Calculate the delta of 'input_vector' as + * 'delta' = 'input_vector' * 'weights_vector' + * + * To calculate 'delta' over a ring buffer of 'input_vector', replicate + * the 'weights_vector' at the end (which memory size is now + * 2*'filter_size') and use (weights_vector + filter_size - 1 - + * current_input) as 'weights_vector' start pointer. + * + * @param delta is a scalar + * @param input_vector size is 'filter_size' + * @param weights_vector size is 'filter_size' + * @param filter_size is the number of points to evaluate the delta + */ +void rta_delta(rta_real_t * delta, const rta_real_t * input_vector, + const rta_real_t * weights_vector, + const unsigned int filter_size); + +/** + * Calculate the delta of 'input_vector' as + * 'delta' = 'input_vector' * 'weights_vector' + * + * To calculate 'delta' over a ring buffer of 'input_vector', replicate + * the 'weights_vector' at the end (which memory size is now + * 2*'filter_size') and use (weights_vector + filter_size - 1 - + * current_input) as 'weights_vector' start pointer. + * + * @param delta is a scalar + * @param input_vector size is 'filter_size' + * @param i_stride is 'input_vector' stride + * @param weights_vector size is 'filter_size' + * @param w_stride is 'weights_vector' stride + * @param filter_size is the number of points to evaluate the delta + */ +void rta_delta_stride(rta_real_t * delta, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int filter_size); + + +/** + * Calculate the deltas of 'input_matrix' as + * 'delta' = 'input_matrix' * 'weights_vector' + * + * To calculate 'delta' over a ring buffer of rows 'input_matrix', + * replicate the 'weights_vector' at the end (which memory size is now + * 2*'filter_size') and use (weights_vector + filter_size - 1 - + * current_input) as 'weights_vector' start pointer. + * + * @param delta size is 'input_size' + * @param input_matrix size is 'filter_size'*'input_size'. It is a vector + * of inputs as rows + * @param input_size is the 'input_matrix' rows number and 'delta' size + * @param weights_vector size is 'filter_size' + * @param filter_size is 'input_matrix' columns number, which is the + * number of points to evaluate the deltas + */ +void rta_delta_vector(rta_real_t * delta, + const rta_real_t * input_matrix, const unsigned int input_size, + const rta_real_t * weights_vector, const unsigned int filter_size); + +/** + * Calculate the deltas of 'input_matrix' as + * 'delta' = 'input_matrix' * 'weights_vector' + * + * To calculate 'delta' over a ring buffer of rows 'input_matrix', + * replicate the 'weights_vector' at the end (which memory size is now + * 2*'filter_size') and use (weights_vector + filter_size - 1 - + * current_input) as 'weights_vector' start pointer. + * + * @param delta size is 'input_size' + * @param d_stride is 'delta' stride + * @param input_matrix size is 'filter_size'*'input_size'. It is a vector + * of inputs as rows + * @param i_stride is 'input_matrix' stride + * @param input_size is the 'input_matrix' rows number and 'delta' size + * @param weights_vector size is 'filter_size' + * @param w_stride is 'weights_vector' stride + * @param filter_size is 'input_matrix' columns number, which is the + * number of points to evaluate the deltas + */ +void rta_delta_vector_stride(rta_real_t * delta, const int d_stride, + const rta_real_t * input_matrix, const int i_stride, + const unsigned int input_size, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int filter_size); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_DELTA_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_fft.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_fft.c new file mode 100644 index 0000000000000000000000000000000000000000..3937ad39a83ee44535ceec78a2c2bec463178cfe --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_fft.c @@ -0,0 +1,1595 @@ +/** + * @file rta_fft.c + * @author Jean-Philippe Lambert + * @date Thu Sep 12 18:10:41 2007 + * + * @brief Fast Fourier Transform + * + * Based on FTM (FTS) FFT routines. + * @see http://ftm.ircam.fr + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_fft.h" +#include "rta_complex.h" +#include "rta_stdlib.h" /* memory management */ + +#include "rta_int.h" /* integer log2 function */ +#include "rta_math.h" /* M_PI, cos, sin */ + +/* ------- private (depends on implementation) ------ */ +/* from FTS implementation (Butterfly) */ +struct rta_fft_setup +{ + void * output; + int o_stride; + unsigned int fft_size; + void * input; + int i_stride; + unsigned int input_size; + unsigned int log2_size; + rta_fft_t fft_type; + rta_real_t * nyquist; /**< last coefficient for real transforms */ + rta_real_t * scale; + rta_real_t * cos; + rta_real_t * sin; + unsigned int * bitrev; +}; /* from fft_lookup_t */ + + +/* bitreversal with oversampled index table */ +/* from cfft_bitreversal_over_inplc */ +static void +bitreversal_oversampled_inplace(rta_complex_t * buf, + const unsigned int * bitrev, + const unsigned int size) +{ + unsigned int idx; + rta_complex_t z; + + for(idx=0; idx<size; idx++) + { + unsigned int xdi = bitrev[2 * idx]; + + if(xdi > idx) + { + z = buf[idx]; + buf[idx] = buf[xdi]; + buf[xdi] = z; + } + } + return; +} + +static void +bitreversal_oversampled_inplace_stride(rta_complex_t * buf, + const int b_stride, + const unsigned int * bitrev, + const unsigned int size) +{ + unsigned int idx; + rta_complex_t z; + + for(idx=0; idx<size; idx++) + { + unsigned int xdi = bitrev[2 * idx]; + + if(xdi > idx) + { + int idx_tmp = idx * b_stride; + xdi *= b_stride; + z = buf[idx_tmp]; + buf[idx_tmp] = buf[xdi]; + buf[xdi] = z; + } + } + return; +} + +/* from cfft_bitreversal_inplc */ +static void +bitreversal_inplace(rta_complex_t * buf, + const unsigned int * bitrev, + const unsigned int size) +{ + unsigned int idx; + rta_complex_t z; + + for(idx=0; idx<size; idx++) + { + unsigned int xdi = bitrev[idx]; + if(xdi > idx) + { + z = buf[idx]; + buf[idx] = buf[xdi]; + buf[xdi] = z; + } + } + return; +} + +static void +bitreversal_inplace_stride(rta_complex_t * buf, + const int b_stride, + const unsigned int * bitrev, + const unsigned int size) +{ + unsigned int idx; + rta_complex_t z; + + for(idx=0; idx<size; idx++) + { + unsigned int xdi = bitrev[idx]; + if(xdi > idx) + { + int idx_tmp = idx * b_stride; + xdi *= b_stride; + z = buf[idx_tmp]; + buf[idx_tmp] = buf[xdi]; + buf[xdi] = z; + } + } + return; +} + +/******************************************************************** + * from cfft_inplc: + * + * fft computation on bit reversed shuffled data + * for fft: coef = exp(j*2*PI*n/N), n = 0..N-1 + * for ifft: coef = exp(-j*2*PI*n/N), n = 0..N-1 + * see routine: generate_fft_coefficients() + */ +/* FFT with over-sampled coefficient tables */ +static void +fft_inplace(rta_complex_t * buf, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + unsigned int incr = 2 * up; + + for(m=j, n=j+up; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_cimag(B) * rta_cimag(W) + rta_creal(B) * rta_creal(W), + rta_cimag(B) * rta_creal(W) - rta_creal(B) * rta_cimag(W)); + + buf[m] = rta_add_complex(A , C); + buf[n] = rta_sub_complex(A , C); + } + } + } + return; +} + +/******************************************************************** + * from cfft_inplc: + * + * fft computation on bit reversed shuffled data + * for fft: coef = exp(j*2*PI*n/N), n = 0..N-1 + * for ifft: coef = exp(-j*2*PI*n/N), n = 0..N-1 + * see routine: generate_fft_coefficients() + */ +/* FFT with over-sampled coefficient tables */ +static void +fft_inplace_stride(rta_complex_t * buf, + const int b_stride, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + int incr = 2 * up * b_stride; + + for(m=j*b_stride, n=(j+up)*b_stride; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_cimag(B) * rta_cimag(W) + rta_creal(B) * rta_creal(W), + rta_cimag(B) * rta_creal(W) - rta_creal(B) * rta_cimag(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + + +/* FFT with over-sampled coefficient tables */ +static void +fft_inplace_oversampled_coefficients(rta_complex_t * buf, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=2*down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + unsigned int incr = 2 * up; + + for(m=j, n=j+up; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_cimag(B) * rta_cimag(W) + rta_creal(B) * rta_creal(W), + rta_cimag(B) * rta_creal(W) - rta_creal(B) * rta_cimag(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + +/* FFT with over-sampled coefficient tables */ +static void +fft_inplace_oversampled_coefficients_stride(rta_complex_t * buf, + const int b_stride, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=2*down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + int incr = 2 * up * b_stride; + + for(m=j*b_stride, n=(j+up)*b_stride; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_cimag(B) * rta_cimag(W) + rta_creal(B) * rta_creal(W), + rta_cimag(B) * rta_creal(W) - rta_creal(B) * rta_cimag(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + +static void +ifft_inplace(rta_complex_t * buf, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + unsigned int incr = 2 * up; + + for(m=j, n=j+up; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_creal(B) * rta_creal(W) - rta_cimag(B) * rta_cimag(W), + rta_creal(B) * rta_cimag(W) + rta_cimag(B) * rta_creal(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + +static void +ifft_inplace_stride(rta_complex_t * buf, + const int b_stride, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + int incr = 2 * up * b_stride; + + for(m=j*b_stride, n=(j+up)*b_stride; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_creal(B) * rta_creal(W) - rta_cimag(B) * rta_cimag(W), + rta_creal(B) * rta_cimag(W) + rta_cimag(B) * rta_creal(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + + +static void +ifft_inplace_oversampled_coefficients(rta_complex_t * buf, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=2*down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + unsigned int incr = 2 * up; + + for(m=j, n=j+up; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_creal(B) * rta_creal(W) - rta_cimag(B) * rta_cimag(W), + rta_creal(B) * rta_cimag(W) + rta_cimag(B) * rta_creal(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + +static void +ifft_inplace_oversampled_coefficients_stride(rta_complex_t * buf, + const int b_stride, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const unsigned int size) +{ + unsigned int m, n; + unsigned int j, k, up, down; + + for(up=1, down=size>>1; up<size; up<<=1, down>>=1) + { + for(j=0, k=0; j<up; j++, k+=2*down) + { + //rta_complex_t W = coef_real[k] + coef_imag[k] *I; + rta_complex_t W = rta_make_complex(coef_real[k], coef_imag[k]); + + int incr = 2 * up * b_stride; + + for(m=j*b_stride, n=(j+up)*b_stride; m<size; m+=incr, n+=incr) + { + rta_complex_t A = buf[m]; + rta_complex_t B = buf[n]; + + rta_complex_t C = rta_make_complex(rta_creal(B) * rta_creal(W) - rta_cimag(B) * rta_cimag(W), + rta_creal(B) * rta_cimag(W) + rta_cimag(B) * rta_creal(W)); + + buf[m] = rta_add_complex(A, C); + buf[n] = rta_sub_complex(A, C); + } + } + } + return; +} + + +/* from rfft_shuffle_after_fft_inplc */ +/************************************************************************** + * + * rfft_shuffle_after_fft() and rfft_shuffle_befor_ifft() + * + * shuffling routines to compute the positive half of a spectra out of the FFT + * of a 2*N points real signal treated as real and imaginary part of a complex + * signal and vice versa: + * + * with: + * X+ = rfft_shuffle_after_fft(S, ...) ... use after complex FFT + * and: + * S = rfft_shuffle_befor_ifft(X+, ...) ... use befor complex IFFT + * + * where: + * x[m], m = 0..2*N-1 ... real signal + * X+[k], k = 0..N-1 ... positive part of spectrum of x[m] + * and: + * s[n] = x[2n] + j x[2n+1], n = 0..N-1 ... real signal as complex vector + * S[k], k = 0..N-1 ... complex FFT of complex vector s[n] + * + * + * arguments: + * buf ... buffer for inplace shuffling + * in, out ... input vector, output vector for non inplace shuffling + * coef_re ... lookup table with cos(2*PI*i/size), i = 0 ... size/2-1 + * coef_im ... lookup table with sin(2*PI*i/size), i = 0 ... size/2-1 + * size ... # of complex points (cfft size) + * (Note: the lookup tables just contain half of the sine/cosine period in size points) + */ +static void +shuffle_after_real_fft_inplace(rta_complex_t * buf, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const int size) +{ + int idx, xdi; + + /* nyquist point coded in imaginary part first point */ + buf[0] = rta_make_complex(rta_creal(buf[0]) + rta_cimag(buf[0]), rta_creal(buf[0]) - rta_cimag(buf[0])); + + + for(idx=1, xdi=size-1; idx<size/2; idx++, xdi--) + { + rta_real_t x1_real = 0.5*(rta_creal(buf[idx]) + rta_creal(buf[xdi])); + rta_real_t x1_imag = 0.5*(rta_cimag(buf[idx]) - rta_cimag(buf[xdi])); + + rta_real_t x2_real = 0.5*(rta_cimag(buf[xdi]) + rta_cimag(buf[idx])); + rta_real_t x2_imag = 0.5*(rta_creal(buf[xdi]) - rta_creal(buf[idx])); + + /* real of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_real = x2_imag * coef_imag[idx] + x2_real * coef_real[idx]; + + /* imaginary of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_imag = x2_imag * coef_real[idx] - x2_real * coef_imag[idx]; + + buf[idx] = rta_make_complex(x1_real + x2Ej_real, x1_imag + x2Ej_imag); + buf[xdi] = rta_make_complex(x1_real - x2Ej_real, x2Ej_imag - x1_imag); + } + + buf[idx] = rta_conj(buf[idx]); + return; +} + +static void +shuffle_after_real_fft_inplace_stride(rta_complex_t * buf, + const int b_stride, + const rta_real_t * coef_real, + const rta_real_t * coef_imag, + const int size) +{ + int idx; + int idx_s, xdi_s; /* indexes * b_stride */ + + /* nyquist point coded in imaginary part first point */ + buf[0] = rta_make_complex(rta_creal(buf[0]) + rta_cimag(buf[0]), rta_creal(buf[0]) - rta_cimag(buf[0])); + + for(idx=1, idx_s=b_stride, xdi_s=(size-1)*b_stride; + idx<size/2; + idx++, idx_s+=b_stride, xdi_s-=b_stride) + { + rta_real_t x1_real = 0.5*(rta_creal(buf[idx_s]) + rta_creal(buf[xdi_s])); + rta_real_t x1_imag = 0.5*(rta_cimag(buf[idx_s]) - rta_cimag(buf[xdi_s])); + + rta_real_t x2_real = 0.5*(rta_cimag(buf[xdi_s]) + rta_cimag(buf[idx_s])); + rta_real_t x2_imag = 0.5*(rta_creal(buf[xdi_s]) - rta_creal(buf[idx_s])); + + /* real of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_real = x2_imag * coef_imag[idx] + x2_real * coef_real[idx]; + + /* imaginary of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_imag = x2_imag * coef_real[idx] - x2_real * coef_imag[idx]; + + buf[idx_s] = rta_make_complex(x1_real + x2Ej_real, x1_imag + x2Ej_imag); + buf[xdi_s] = rta_make_complex(x1_real - x2Ej_real, x2Ej_imag - x1_imag); + } + + buf[idx_s] = rta_conj(buf[idx_s]); + return; +} + +/* from rfft_shuffle_before_ifft_inplc */ +static void +shuffle_before_real_inverse_fft_inplace(rta_complex_t * buf, + const rta_real_t *coef_real, + const rta_real_t *coef_imag, + const int size) +{ + int idx, xdi; + + /* nyquist point coded in imaginary part of the first point */ + buf[0] = rta_make_complex(rta_creal(buf[0]) + rta_cimag(buf[0]), rta_creal(buf[0]) - rta_cimag(buf[0])); + + for(idx=1, xdi=size-1; idx<size/2; idx++, xdi--) + { + rta_real_t x1_real = rta_creal(buf[idx]) + rta_creal(buf[xdi]); + rta_real_t x1_imag = rta_cimag(buf[idx]) - rta_cimag(buf[xdi]); + + /* real of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_real = rta_creal(buf[idx]) - rta_creal(buf[xdi]); + + /* imaginary of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_imag = rta_cimag(buf[idx]) + rta_cimag(buf[xdi]); + + /* real of x2 */ + rta_real_t x2_real = x2Ej_real * coef_real[idx] - x2Ej_imag * coef_imag[idx]; + + /* imaginary of x2 */ + rta_real_t x2_imag = x2Ej_real * coef_imag[idx] + x2Ej_imag * coef_real[idx]; + + buf[idx] = rta_make_complex(x1_real - x2_imag, x1_imag + x2_real); + buf[xdi] = rta_make_complex(x1_real + x2_imag, x2_real - x1_imag); + + } + buf[idx] = rta_mul_complex_real(rta_conj(buf[idx]), 2); + return; +} + +static void +shuffle_before_real_inverse_fft_inplace_stride(rta_complex_t * buf, + const int b_stride, + const rta_real_t *coef_real, + const rta_real_t *coef_imag, + const int size) +{ + int idx; + int idx_s, xdi_s; /* indexes * b_stride */ + + /* nyquist point coded in imaginary part of the first point */ + buf[0] = rta_make_complex(rta_creal(buf[0]) + rta_cimag(buf[0]), rta_creal(buf[0]) - rta_cimag(buf[0])); + + for(idx=1, idx_s=b_stride, xdi_s=(size-1)*b_stride; + idx<size/2; + idx++, idx_s+=b_stride, xdi_s-=b_stride) + { + rta_real_t x1_real = rta_creal(buf[idx_s]) + rta_creal(buf[xdi_s]); + rta_real_t x1_imag = rta_cimag(buf[idx_s]) - rta_cimag(buf[xdi_s]); + + /* real of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_real = rta_creal(buf[idx_s]) - rta_creal(buf[xdi_s]); + + /* imaginary of x2[idx] * exp(-j*PI*i/size) */ + rta_real_t x2Ej_imag = rta_cimag(buf[idx_s]) + rta_cimag(buf[xdi_s]); + + /* real of x2 */ + rta_real_t x2_real = x2Ej_real * coef_real[idx] - x2Ej_imag * coef_imag[idx]; + + /* imaginary of x2 */ + rta_real_t x2_imag = x2Ej_real * coef_imag[idx] + x2Ej_imag * coef_real[idx]; + + buf[idx_s] = rta_make_complex(x1_real - x2_imag, x1_imag + x2_real); + buf[xdi_s] = rta_make_complex(x1_real + x2_imag, x2_real - x1_imag); + + } + buf[idx_s] = rta_mul_complex_real(rta_conj(buf[idx_s]), 2); + return; +} + + +/* FTS fill_real */ +static void +fill_real_scale_zero_pad(rta_real_t * output, const unsigned int output_size, + rta_real_t * input, const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size; i++) + { + output[i] = input[i] * scale; + } + } + else + { + for (i = 0; i < used_input_size; i++) + { + output[i] = input[i]; + } + } + + /* zero padding */ + for(; i<output_size; i++) + { + output[i] = 0.0; + } + return; +} + +static void +fill_real_scale_zero_pad_stride( + rta_real_t * output, const int o_stride, const unsigned int output_size, + rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int o, i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0, o=0; i<used_input_size*i_stride; i+=i_stride, o+=o_stride) + { + output[o] = input[i] * scale; + } + } + else + { + for(i=0, o=0; i<used_input_size*i_stride; i+=i_stride, o+=o_stride) + { + output[o] = input[i]; + } + } + + /* zero padding */ + for(; o<output_size*o_stride; o+=o_stride) + { + output[o] = 0.0; + } + return; +} + +/* FTS fill_complex */ +static void +fill_complex_scale_zero_pad(rta_complex_t * output, const unsigned int output_size, + rta_complex_t * input, const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size; i++) + { + output[i] = rta_mul_complex_real(input[i], scale); + } + } + else + { + for(i=0; i<used_input_size; i++) + { + output[i] = input[i]; + } + } + + /* zero padding */ + for(; i<output_size; i++) + { + rta_set_complex_real(output[i], 0.0); + } + return; +} + +static void +fill_complex_scale_zero_pad_stride( + rta_complex_t * output, const int o_stride, const unsigned int output_size, + rta_complex_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i, o; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0, o=0; i<used_input_size*i_stride; i+=i_stride, o+=o_stride) + { + output[o] = rta_mul_complex_real(input[i], scale); + } + } + else + { + for(i=0, o=0; i<used_input_size*i_stride; i+=i_stride, o+=o_stride) + { + output[o] = input[i]; + } + } + + /* zero padding */ + for(; o<output_size*o_stride; o+=o_stride) + { + rta_set_complex_real(output[o], 0.0); + } + return; +} + + +static void +fill_complex_from_real_scale_zero_pad( + rta_complex_t * output, const unsigned int output_size, + rta_real_t * input, const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size; i++) + { + rta_set_complex_real(output[i], input[i] * scale); + } + } + else + { + for (i = 0; i < used_input_size; i++) + { + rta_set_complex_real(output[i], input[i]); + } + } + + /* zero padding */ + for(; i<output_size; i++) + { + rta_set_complex_real(output[i], 0.0); + } + return; +} + +static void +fill_complex_from_real_scale_zero_pad_stride( + rta_complex_t * output, const int o_stride, const unsigned int output_size, + rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i, o; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0, o=0; i<used_input_size*i_stride; i+=i_stride, o+=o_stride) + { + rta_set_complex_real(output[o], input[i] * scale); + } + } + else + { + for(i=0, o=0; i<used_input_size*i_stride; i+=i_stride, o+=o_stride) + { + rta_set_complex_real(output[o], input[i]); + } + } + + /* zero padding */ + for(; o<output_size*o_stride; o+=o_stride) + { + rta_set_complex_real(output[o], 0.0); + } + return; +} + + +static void +scale_real_zero_pad_in_place(rta_real_t * buf, const unsigned int output_size, + const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size; i++) + { + buf[i] *= scale; + } + } + else + { + i = used_input_size; + } + + /* zero padding */ + for(; i<output_size; i++) + { + buf[i] = 0.0; + } + return; +} + +static void +scale_real_zero_pad_in_place_stride( + rta_real_t * buf, const int b_stride, const unsigned int output_size, + const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size*b_stride; i+=b_stride) + { + buf[i] *= scale; + } + } + else + { + i = used_input_size*b_stride; + } + + /* zero padding */ + for(; i<output_size*b_stride; i+=b_stride) + { + buf[i] = 0.0; + } + return; +} + + +static void +scale_complex_zero_pad_in_place(rta_complex_t * buf, const unsigned int output_size, + const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size; i++) + { + buf[i] = rta_mul_complex_real(buf[i], scale); + } + } + else + { + i = used_input_size; + } + + /* zero padding */ + for(; i<output_size; i++) + { + rta_set_complex_real(buf[i], 0.0); + } + return; +} + +static void +scale_complex_zero_pad_in_place_stride( + rta_complex_t * buf, const int b_stride, const unsigned int output_size, + const unsigned int input_size, + const rta_real_t scale) +{ + unsigned int i; + unsigned int used_input_size; + + if(input_size > output_size) + { + used_input_size = output_size; + } + else + { + used_input_size = input_size; + } + + if(scale != 1.) + { + for(i=0; i<used_input_size*b_stride; i+=b_stride) + { + buf[i] = rta_mul_complex_real(buf[i], scale); + } + } + else + { + i = used_input_size*b_stride; + } + + /* zero padding */ + for(; i<output_size*b_stride; i+=b_stride) + { + rta_set_complex_real(buf[i], 0.0); + } + return; +} + + + +/* sine, cosine and bitreverse tables */ +/* retrun 1 on success, 0 on fail */ +static int +tables_new(rta_fft_setup_t * fft_setup) +{ + int ret = 0; + /* sine (and cosine) table */ + + /* 1/4 more for cosine as phase shift and one more point at the end */ + /* => total size is 5/4*sine_size + 1 */ + fft_setup->sin = (rta_real_t *) rta_malloc( + sizeof(rta_real_t) * (fft_setup->fft_size * 5/4 + 1)); + + if(fft_setup->sin != NULL) + { + /* sine function from 0 to 2pi, inclusive (plus 1/4 for cosine) */ + /* step = 5/4 * 2 pi / (5/4 * size) = 2 * pi / size */ + const rta_real_t step = 2. * M_PI / fft_setup->fft_size; + unsigned int i; + for(i=0; i<=fft_setup->fft_size * 5/4; i++) + { + fft_setup->sin[i] = rta_sin(i*step); + } + + /* cosine function is just a phase-shifted sine */ + /* Memory is shared */ + fft_setup->cos = fft_setup->sin + (fft_setup->fft_size / 4); + + /* Bit reversal table */ + fft_setup->bitrev = (unsigned int *) rta_malloc( + sizeof(unsigned int) * fft_setup->fft_size); + + if(fft_setup->bitrev != NULL) + { + unsigned int idx, xdi; + unsigned int i, j; + + for(i=0; i<fft_setup->fft_size; i++) + { + idx = i; + xdi = 0; + + for(j=1; j<fft_setup->log2_size; j++) + { + xdi += (idx & 1); + xdi <<= 1; + idx >>= 1; + } + + fft_setup->bitrev[i] = xdi + (idx & 1); + } + + ret = 1; /* setup complete */ + } + else /* bitrev failed */ + rta_free(fft_setup->sin); + } + /* else: sin failed */ + + return ret; +} + +/* ------- end of private ---------------------------- */ + +/* ------- Public functions -------------------------- */ + +int +rta_fft_real_setup_new(rta_fft_setup_t ** fft_setup, + const rta_fft_t fft_type, rta_real_t * scale, + void * input, const unsigned int input_size, + void * output, const unsigned int fft_size, + rta_real_t * nyquist) +/* FFTW uses input and output to plan executions */ +{ + int ret = 0; + + *fft_setup = (rta_fft_setup_t *) rta_malloc(sizeof(rta_fft_setup_t)); + + if(*fft_setup != NULL) + { + /* actual FFT size is the next power of 2 of the given argument */ + (*fft_setup)->fft_size = rta_inextpow2(fft_size); + (*fft_setup)->log2_size = rta_ilog2((*fft_setup)->fft_size); + (*fft_setup)->input_size = input_size; + + (*fft_setup)->output = output; + (*fft_setup)->o_stride = 1; + + (*fft_setup)->input = input; + (*fft_setup)->i_stride = 1; + + (*fft_setup)->nyquist = nyquist; + + (*fft_setup)->scale = scale; + (*fft_setup)->fft_type = fft_type; + + ret = tables_new(*fft_setup); + if(ret == 0) + { + rta_free(*fft_setup); + *fft_setup = NULL; + } + } + + return ret; +} + +int +rta_fft_real_setup_new_stride( + rta_fft_setup_t ** fft_setup, + const rta_fft_t fft_type, rta_real_t * scale, + void * input, const int i_stride, const unsigned int input_size, + void * output, const int o_stride, const unsigned int fft_size, + rta_real_t * nyquist) +/* FFTW uses input and output to plan executions */ +{ + int ret = 0; + + *fft_setup = (rta_fft_setup_t *) rta_malloc(sizeof(rta_fft_setup_t)); + + if(fft_setup != NULL) + { + /* actual FFT size is the next power of 2 of the given argument */ + (*fft_setup)->fft_size = rta_inextpow2(fft_size); + (*fft_setup)->log2_size = rta_ilog2((*fft_setup)->fft_size); + (*fft_setup)->input_size = input_size; + + (*fft_setup)->output = output; + (*fft_setup)->o_stride = o_stride; + + (*fft_setup)->input = input; + (*fft_setup)->i_stride = i_stride; + + (*fft_setup)->nyquist = nyquist; + + (*fft_setup)->scale = scale; + (*fft_setup)->fft_type = fft_type; + + ret = tables_new(*fft_setup); + if(ret == 0) + { + rta_free(*fft_setup); + *fft_setup = NULL; + } + } + + return ret; +} + +int +rta_fft_setup_new(rta_fft_setup_t ** fft_setup, + const rta_fft_t fft_type, rta_real_t * scale, + rta_complex_t * input, const unsigned int input_size, + rta_complex_t * output, const unsigned int fft_size) +/* FFTW uses input and output to plan executions */ +{ + int ret = 0; + + *fft_setup = (rta_fft_setup_t *) rta_malloc(sizeof(rta_fft_setup_t)); + + if(*fft_setup != NULL) + { + /* actual FFT size is the next power of 2 of the given argument */ + (*fft_setup)->fft_size = rta_inextpow2(fft_size); + (*fft_setup)->log2_size = rta_ilog2((*fft_setup)->fft_size); + (*fft_setup)->input_size = input_size; + + (*fft_setup)->output = (void *) output; + (*fft_setup)->o_stride = 1; + + (*fft_setup)->input = (void *) input; + (*fft_setup)->i_stride = 1; + + (*fft_setup)->nyquist = NULL; + + (*fft_setup)->scale = scale; + (*fft_setup)->fft_type = fft_type; + + ret = tables_new(*fft_setup); + if(ret == 0) + { + rta_free(*fft_setup); + *fft_setup = NULL; + } + } + + return ret; +} + +int +rta_fft_setup_new_stride( + rta_fft_setup_t ** fft_setup, + const rta_fft_t fft_type, rta_real_t * scale, + rta_complex_t * input, const int i_stride, const unsigned int input_size, + rta_complex_t * output, const int o_stride, const unsigned int fft_size) +/* FFTW uses input and output to plan executions */ +{ + int ret = 0; + + *fft_setup = (rta_fft_setup_t *) rta_malloc(sizeof(rta_fft_setup_t)); + + if(*fft_setup != NULL) + { + /* actual FFT size is the next power of 2 of the given argument */ + (*fft_setup)->fft_size = rta_inextpow2(fft_size); + (*fft_setup)->log2_size = rta_ilog2((*fft_setup)->fft_size); + (*fft_setup)->input_size = input_size; + + (*fft_setup)->output = (void *) output; + (*fft_setup)->o_stride = o_stride; + + (*fft_setup)->input = (void *) input; + (*fft_setup)->i_stride = i_stride; + + (*fft_setup)->nyquist = NULL; + + (*fft_setup)->scale = scale; + (*fft_setup)->fft_type = fft_type; + + ret = tables_new(*fft_setup); + if(ret == 0) + { + rta_free(*fft_setup); + *fft_setup = NULL; + } + } + + return ret; +} + + +void +rta_fft_setup_delete(rta_fft_setup_t * fft_setup) +{ + if(fft_setup != NULL) + { + if(fft_setup->sin != NULL) + { + rta_free(fft_setup->sin); + } + + if(fft_setup->bitrev != NULL) + { + rta_free(fft_setup->bitrev); + } + + rta_free(fft_setup); + } + + return; +} + + +void +rta_fft_execute(void * output, void * input, const unsigned int input_size, + rta_fft_setup_t * fft_setup) +{ + const unsigned int no_stride = + fft_setup->i_stride == 1 && fft_setup->o_stride == 1; + unsigned int spectrum_size = fft_setup->fft_size >> 1; + fft_setup->input = input; + fft_setup->output = output; + fft_setup->input_size = input_size; + + switch(fft_setup->fft_type) + { + case rta_fft_real_to_complex_1d: + { + rta_real_t * real_input = (rta_real_t *) fft_setup->input; + rta_complex_t * complex_output = (rta_complex_t *) fft_setup->output; + + /* out of place transform */ + if(fft_setup->input != fft_setup->output) + { + /* at this moment, the output buffer is real, as the input one */ + if(no_stride) + { + fill_real_scale_zero_pad( + (rta_real_t *) fft_setup->output, fft_setup->fft_size, + real_input, fft_setup->input_size, *(fft_setup->scale)); + } + else + { + fill_real_scale_zero_pad_stride( + (rta_real_t *) fft_setup->output, fft_setup->o_stride, + fft_setup->fft_size, + real_input, fft_setup->i_stride, fft_setup->input_size, + *(fft_setup->scale)); + } + } + else + { + if(no_stride) + { + scale_real_zero_pad_in_place( + real_input, fft_setup->fft_size, + fft_setup->input_size, *(fft_setup->scale)); + } + else + { + /* for in place transforms, fft_setup->o_stride and */ + /* fft_setup->i_stride must be the equal */ + scale_real_zero_pad_in_place_stride( + real_input, fft_setup->i_stride, fft_setup->fft_size, + fft_setup->input_size, *(fft_setup->scale)); + } + } + + if(fft_setup->o_stride == 1) + { + bitreversal_oversampled_inplace( + complex_output, fft_setup->bitrev, spectrum_size); + + fft_inplace_oversampled_coefficients( + complex_output, fft_setup->cos, fft_setup->sin, spectrum_size); + + shuffle_after_real_fft_inplace( + complex_output, fft_setup->cos, fft_setup->sin, spectrum_size); + } + else + { + bitreversal_oversampled_inplace_stride( + complex_output, fft_setup->o_stride, fft_setup->bitrev, spectrum_size); + + fft_inplace_oversampled_coefficients_stride( + complex_output, fft_setup->o_stride, + fft_setup->cos, fft_setup->sin, spectrum_size); + + shuffle_after_real_fft_inplace_stride( + complex_output, fft_setup->o_stride, + fft_setup->cos, fft_setup->sin, spectrum_size); + + } + *(fft_setup->nyquist) = rta_cimag(complex_output[0]); + rta_set_complex_real(complex_output[0], rta_creal(complex_output[0])); + + break; + } + + case rta_fft_complex_to_real_1d: + { + rta_complex_t * complex_input = (rta_complex_t *) fft_setup->input; + rta_real_t * real_output = (rta_real_t *) fft_setup->output; + rta_complex_t * complex_output = (rta_complex_t *) fft_setup->output; + + /* out of place transform */ + if(fft_setup->input != fft_setup->output) + { + if(no_stride) + { + fill_complex_scale_zero_pad( + complex_output, spectrum_size, + complex_input, fft_setup->input_size, *(fft_setup->scale)); + } + else + { + fill_complex_scale_zero_pad_stride( + complex_output, fft_setup->o_stride, spectrum_size, + complex_input, fft_setup->i_stride, fft_setup->input_size, + *(fft_setup->scale)); + } + } + else + { + if(no_stride) + { + scale_complex_zero_pad_in_place( + complex_input, spectrum_size, + fft_setup->input_size,*(fft_setup->scale)); + } + else + { + /* for in place transforms, fft_setup->o_stride and */ + /* fft_setup->i_stride must be the equal */ + scale_complex_zero_pad_in_place_stride( + complex_input, fft_setup->i_stride, spectrum_size, + fft_setup->input_size,*(fft_setup->scale)); + } + } + + /* nyquist value is coded on the first imaginary value */ + /* there is no stride here: real and imaginary values of the */ + /* complex type must be contiguous */ + if(*(fft_setup->scale) != 1.) + { + real_output[1] = *(fft_setup->nyquist) * *(fft_setup->scale); + } + else + { + real_output[1] = *(fft_setup->nyquist); + } + + if(fft_setup->o_stride == 1) + { + shuffle_before_real_inverse_fft_inplace( + complex_output, fft_setup->cos, fft_setup->sin, spectrum_size); + + bitreversal_oversampled_inplace( + complex_output, fft_setup->bitrev, spectrum_size); + + ifft_inplace_oversampled_coefficients( + complex_output, fft_setup->cos, fft_setup->sin, spectrum_size); + } + else + { + shuffle_before_real_inverse_fft_inplace_stride( + complex_output, fft_setup->o_stride, + fft_setup->cos, fft_setup->sin, spectrum_size); + + bitreversal_oversampled_inplace_stride( + complex_output, fft_setup->o_stride, + fft_setup->bitrev, spectrum_size); + + ifft_inplace_oversampled_coefficients_stride( + complex_output, fft_setup->o_stride, + fft_setup->cos, fft_setup->sin, spectrum_size); + } + + break; + } + + case rta_fft_complex_1d: + { + rta_complex_t * complex_input = (rta_complex_t *) fft_setup->input; + rta_complex_t * complex_output = (rta_complex_t *) fft_setup->output; + + /* out of place transform */ + if(fft_setup->input != fft_setup->output) + { + if(no_stride) + { + fill_complex_scale_zero_pad( + complex_output, fft_setup->fft_size, + complex_input, fft_setup->input_size, *(fft_setup->scale)); + } + else + { + fill_complex_scale_zero_pad_stride( + complex_output, fft_setup->o_stride, fft_setup->fft_size, + complex_input, fft_setup->i_stride, fft_setup->input_size, + *(fft_setup->scale)); + } + } + else + { + if(no_stride) + { + scale_complex_zero_pad_in_place( + complex_input, fft_setup->fft_size, + fft_setup->input_size,*(fft_setup->scale)); + } + else + { + /* for in place transforms, fft_setup->o_stride and */ + /* fft_setup->i_stride must be the equal */ + scale_complex_zero_pad_in_place_stride( + complex_input, fft_setup->i_stride, fft_setup->fft_size, + fft_setup->input_size,*(fft_setup->scale)); + } + } + + if(fft_setup->o_stride == 1) + { + bitreversal_inplace(complex_output, fft_setup->bitrev, fft_setup->fft_size); + + fft_inplace(complex_output, fft_setup->cos, fft_setup->sin, fft_setup->fft_size); + } + else + { + bitreversal_inplace_stride(complex_output, fft_setup->o_stride, + fft_setup->bitrev, fft_setup->fft_size); + + fft_inplace_stride(complex_output, fft_setup->o_stride, + fft_setup->cos, fft_setup->sin, fft_setup->fft_size); + } + + break; + } + + case rta_fft_complex_inverse_1d: + { + rta_complex_t * complex_input = (rta_complex_t *) fft_setup->input; + rta_complex_t * complex_output = (rta_complex_t *) fft_setup->output; + + /* out of place transform */ + if(fft_setup->input != fft_setup->output) + { + if(no_stride) + { + fill_complex_scale_zero_pad( + complex_output, fft_setup->fft_size, + complex_input, fft_setup->input_size, *(fft_setup->scale)); + } + else + { + fill_complex_scale_zero_pad_stride( + complex_output, fft_setup->o_stride, fft_setup->fft_size, + complex_input, fft_setup->i_stride, fft_setup->input_size, + *(fft_setup->scale)); + } + } + else + { + if(no_stride) + { + scale_complex_zero_pad_in_place( + complex_input, fft_setup->fft_size, + fft_setup->input_size,*(fft_setup->scale)); + } + else + { + /* for in place transforms, fft_setup->o_stride and */ + /* fft_setup->i_stride must be the equal */ + scale_complex_zero_pad_in_place_stride( + complex_input, fft_setup->i_stride, fft_setup->fft_size, + fft_setup->input_size,*(fft_setup->scale)); + } + } + + if(fft_setup->o_stride == 1) + { + bitreversal_inplace( + complex_output, fft_setup->bitrev, fft_setup->fft_size); + + ifft_inplace( + complex_output, fft_setup->cos, fft_setup->sin, fft_setup->fft_size); + } + else + { + bitreversal_inplace_stride(complex_output, fft_setup->o_stride, + fft_setup->bitrev, fft_setup->fft_size); + ifft_inplace_stride(complex_output, fft_setup->o_stride, + fft_setup->cos, fft_setup->sin, fft_setup->fft_size); + } + + break; + } + + default: + break; + } + return; +} + +inline void +rta_fft_real_execute(void * output, void * input, const unsigned int input_size, + rta_fft_setup_t * fft_setup, + rta_real_t * nyquist) +{ + fft_setup->nyquist = nyquist; + rta_fft_execute(output, input, input_size, fft_setup); + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_fft.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_fft.h new file mode 100644 index 0000000000000000000000000000000000000000..0a2f84d71ecaa5088094c4aebddad3d8740fd48f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_fft.h @@ -0,0 +1,316 @@ +/** + * @file rta_fft.h + * @author Jean-Philippe Lambert + * @date Thu Sep 12 18:10:41 2007 + * + * @brief Fast Fourier Transform + * + * Based on FTM (based on FTS) FFT routines. + * @see http://ftm.ircam.fr + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_FFT_H_ +#define _RTA_FFT_H_ 1 + +#include "rta.h" +#include "rta_complex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + rta_fft_real_to_complex_1d = 1, /**< real to complex direct transform */ + rta_fft_complex_to_real_1d = 2, /**< complex to real inverse transform */ + rta_fft_complex_1d = 3, /**< complex to complex direct transform */ + rta_fft_complex_inverse_1d = 4 /**< complex to complex inverse transform*/ +} rta_fft_t; + +/* rta_fft_setup is private (depends on implementation) */ +typedef struct rta_fft_setup rta_fft_setup_t; + + +/** + * Allocate and initialize an FFT setup for real to complex or complex + * to real transform, according to the planned processes. + * + * The internal implementation always uses an FFT size of the next (or + * equal) power of 2 of the given 'fft_size'. If the 'input_size is + * smaller than the actual FFT size, it is zero-padded. The use of + * external libraries may differ. + * + * Processing can be in place if 'input' == 'output'. Any real input + * data must be written as real (static cast). + * + * For an out of place transform, 'input' and 'output' must not + * overlap. + * + * \see rta_fft_setup_delete + * + * @param fft_setup is an address of a pointer to a private structure, + * which may depend on the actual FFT implementation. This function + * allocates 'fft_setup' and fills it. + * @param fft_type may be real_to_complex_1d or complex_to_real_1d + * @param scale is usually used for inverse FFT as 1/'fft_size' in + * order to obtain the identity transform when calculating FFT and + * then inverse FFT. It does not need to be constant and may change + * after the setup. + * @param input can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param input_size must be <= 'fft_size' + * @param output can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param fft_size must be >= 'input_size' + * @param nyquist is the last coefficient for real transforms + * + * @return 1 on success 0 on fail. If it fails, nothing should be done + * with 'fft_setup' (even a delete). + */ +int +rta_fft_real_setup_new(rta_fft_setup_t ** fft_setup, + rta_fft_t fft_type, rta_real_t * scale, + void * input, const unsigned int input_size, + void * output, const unsigned int fft_size, + rta_real_t * nyquist); + +/** + * Allocate and initialize an FFT setup for real to complex or complex + * to real transform, according to the planned processes. + * + * The internal implementation always uses an FFT size of the next (or + * equal) power of 2 of the given 'fft_size'. If the 'input_size is + * smaller than the actual FFT size, it is zero-padded. The use of + * external libraries may differ. + * + * Processing can be in place if 'input' == 'output'. Any real input + * data must be written as real (static cast), using 'o_stride'. + * + * For an out of place transform, 'input' and 'output' must not + * overlap and 'i_stride' and 'o_stride' must be equal. + * + * \see rta_fft_setup_delete + * + * @param fft_setup is an address of a pointer to a private structure, + * which may depend on the actual FFT implementation. This function + * allocates 'fft_setup' and fills it. + * @param fft_type may be real_to_complex_1d or complex_to_real_1d + * @param scale is usually used for inverse FFT as 1/'fft_size' in + * order to obtain the identity transform when calculating FFT and + * then inverse FFT. It does not need to be constant and may change + * after the setup. + * @param input can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param i_stride is 'input' stride + * @param input_size must be <= 'fft_size' + * @param output can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param o_stride is 'output' stride + * @param fft_size must be >= 'input_size' + * @param nyquist is the last coefficient for real transforms + * + * @return 1 on success 0 on fail. If it fails, nothing should be done + * with 'fft_setup' (even a delete). + */ +int +rta_fft_real_setup_new_stride( + rta_fft_setup_t ** fft_setup, + rta_fft_t fft_type, rta_real_t * scale, + void * input, const int i_stride, const unsigned int input_size, + void * output, const int o_stride, const unsigned int fft_size, + rta_real_t * nyquist); + +/** + * Allocate and initialize an FFT setup for complex transform, direct + * or inverse, according to the planned processes. + * + * The internal implementation always uses an FFT size of the next (or + * equal) power of 2 of the given 'fft_size'. If the 'input_size is + * smaller than the actual FFT size, it is zero-padded. The use of + * external libraries may differ. + * + * Processing can be in place if 'input' == 'output'. Any real input + * data must be written as complex (real and imaginary values must be + * contiguous, imaginary one being zero). + * + * For an out of place transform, 'input' and 'output' must not + * overlap. + * + * \see rta_fft_setup_delete + * + * @param fft_setup is an address of a pointer to a private structure, + * which may depend on the actual FFT implementation. This function + * allocates 'fft_setup' and fills it. + * @param fft_type may be rta_fft_complex_1d or + * rta_fft_complex_inverse_1d + * @param scale is usually used for inverse FFT as 1/'fft_size' in + * order to obtain the identity transform when calculating FFT and + * then inverse FFT. It does not need to be constant and may change + * after the setup. + * @param input is an array of rta_complex_t. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param input_size must be <= 'fft_size' + * @param output is an array of rta_complex_t. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param fft_size must be >= 'input_size' + * + * @return 1 on success 0 on fail. If it fails, nothing should be done + * with 'fft_setup' (even a delete). + */ +int +rta_fft_setup_new(rta_fft_setup_t ** fft_setup, + rta_fft_t fft_type, rta_real_t * scale, + rta_complex_t * input, const unsigned int input_size, + rta_complex_t * output, const unsigned int fft_size); +/** + * Allocate and initialize an FFT setup for complex transform, direct + * or inverse, according to the planned processes. + * + * The internal implementation always uses an FFT size of the next (or + * equal) power of 2 of the given 'fft_size'. If the 'input_size is + * smaller than the actual FFT size, it is zero-padded. The use of + * external libraries may differ. + * + * Processing can be in place if 'input' == 'output'. (real and + * imaginary values must be contiguous no matter the strides). + * + * For an out of place transform, 'input' and 'output' must not + * overlap. + * + * \see rta_fft_setup_delete + * + * @param fft_setup is an address of a pointer to a private structure, + * which may depend on the actual FFT implementation. This function + * allocates 'fft_setup' and fills it. + * @param fft_type may be rta_fft_complex_1d or + * crta_fft_complex_inverse_1d + * @param scale is usually used for inverse FFT as 1/'fft_size' in + * order to obtain the identity transform when calculating FFT and + * then inverse FFT. It does not need to be constant and may change + * after the setup. + * @param input is an array of rta_complex_t. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param i_stride is 'input' stride + * @param input_size must be <= 'fft_size' + * @param output is an array of rta_complex_t. + * It may be used to determine a proper setup (FFTW) and its content + * may be affected. + * @param o_stride is 'output' stride + * @param fft_size must be >= 'input_size' + * + * @return 1 on success 0 on fail. If it fails, nothing should be done + * with 'fft_setup' (even a delete). + */ +int +rta_fft_setup_new_stride( + rta_fft_setup_t ** fft_setup, + rta_fft_t fft_type, rta_real_t * scale, + rta_complex_t * input, const int i_stride, const unsigned int input_size, + rta_complex_t * output, const int o_stride, const unsigned int fft_size); + +/** + * Deallocate any (sucessfully) allocated FFT setup. + * + * \see rta_fft_setup_new + * + * @param fft_setup is a pointer to the memory wich will be released. + */ +void rta_fft_setup_delete(rta_fft_setup_t * fft_setup); + +/** + * Compute an FFT according to an FFT setup. It is possible to use + * different 'input' and 'output' arguments as those used to + * plan the setup, but they must use exactly the same size and stride. + * + * \see rta_fft_setup_new + * \see rta_fft_real_setup_new + * \see rta_fft_setup_new_stride + * \see rta_fft_real_setup_new_stride + * + * @param output can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * @param input can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * @param input_size is used to perform zero padding, not to resize + * 'input' after a planned setup. + * @param fft_setup is a pointer to a private structure, which may + * depend on the actual FFT implementation. + */ +void rta_fft_execute(void * output, void * input, const unsigned int input_size, + rta_fft_setup_t * fft_setup); + + +/** + * Compute an FFT according to an FFT setup. It is possible to use + * different 'input' and 'output' arguments as those used to + * plan the setup, but they must use exactly the same size and stride. + * + * \see rta_fft_setup_new + * \see rta_fft_real_setup_new + * \see rta_fft_setup_new_stride + * \see rta_fft_real_setup_new_stride + * + * @param output can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * @param input can be an array of rta_real_t or rta_complex_t, + * depending on 'fft_type'. + * @param input_size is used to perform zero padding, not to resize + * 'input' after a planned setup. + * @param fft_setup is a pointer to a private structure, which may + * depend on the actual FFT implementation. + * @param nyquist is the address of the real transform value at the + * Nyquist frequency (for direct and inverse real transforms). + */ +void +rta_fft_real_execute(void * output, void * input, const unsigned int input_size, + rta_fft_setup_t * fft_setup, + rta_real_t * nyquist); + +#ifdef __cplusplus +} +#endif + + +#endif /* _RTA_FFT_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_filter.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..07bb0b1c6c2a05eae334b2bf6646f9061840ee64 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_filter.h @@ -0,0 +1,67 @@ +/** + * @file rta_filter.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Aug 29 12:38:46 2008 + * + * @brief Filter types + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_FILTER_H_ +#define _RTA_FILTER_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum +{ + rta_lowpass = 0, + rta_highpass = 1, + rta_bandpass_constant_skirt = 2, /* msp name: resonant */ + rta_bandpass_constant_peak = 3, /* msp name: bandpass */ + rta_notch = 4, /* msp name: bandstop */ + rta_allpass = 5, + rta_peaking = 6, /* msp name: peaknotch */ + rta_lowshelf = 7, + rta_highshelf = 8 +} rta_filter_t; + + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_FILTER_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lifter.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lifter.c new file mode 100644 index 0000000000000000000000000000000000000000..a0bc63bb31b7e6f4e377a676ed23b02467eecfe8 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lifter.c @@ -0,0 +1,165 @@ +/** + * @file rta_lifter.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Cepstral liftering (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * @see http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_lifter.h" +#include "rta_math.h" + +int rta_lifter_weights(rta_real_t * weights_vector, const unsigned int cepstrum_order, + const rta_real_t liftering_factor, + const rta_lifter_t lifter_t, const rta_lifter_mode_t lifter_m) +{ + int i; + int ret = 1; /* return value */ + + if(lifter_t == rta_lifter_exponential) + { + weights_vector[0] = weights_vector[1] = 1.; + for(i=2; i<cepstrum_order; i++) + { + weights_vector[i] = rta_pow(i, liftering_factor); + } + } + /* HTK-style liftering */ + else if(lifter_t == rta_lifter_sinusoidal) + { + weights_vector[0] = 1.; + for(i=1; i<cepstrum_order; i++) + { + weights_vector[i] = 1. + liftering_factor / 2. * + rta_sin(i * M_PI / liftering_factor); + } + } + else + { + ret = 0; + } + /* inversion */ + if(lifter_m == rta_lifter_mode_inverse) + { + for(i=1; i<cepstrum_order; i++) + { + weights_vector[i] = 1./weights_vector[i]; + } + } + + return ret; +} + +int rta_lifter_weights_stride(rta_real_t * weights_vector, const int w_stride, + const unsigned int cepstrum_order, + const rta_real_t liftering_factor, + const rta_lifter_t lifter_t, const rta_lifter_mode_t lifter_m) +{ + int i; + int ret = 1; /* return value */ + + if(lifter_t == rta_lifter_exponential) + { + weights_vector[0] = weights_vector[w_stride] = 1.; + for(i=2; i<cepstrum_order; i++) + { + weights_vector[i*w_stride] = rta_pow(i, liftering_factor); + } + } + /* HTK-style liftering */ + else if(lifter_t == rta_lifter_sinusoidal) + { + weights_vector[0] = 1.; + for(i=1; i<cepstrum_order; i++) + { + weights_vector[i*w_stride] = 1. + liftering_factor / 2. * + rta_sin(i * M_PI / liftering_factor); + } + } + else + { + ret = 0; + } + /* inversion */ + if(lifter_m == rta_lifter_mode_inverse) + { + for(i=w_stride; i<cepstrum_order*w_stride; i+=w_stride) + { + weights_vector[i] = 1./weights_vector[i]; + } + } + + return ret; +} + + +void rta_lifter_cepstrum(rta_real_t * out_cepstrum, rta_real_t * in_cepstrum, + const rta_real_t * weights_vector, + const unsigned int cepstrum_order) +{ + int i; + for(i=0; i<cepstrum_order; i++) + { + out_cepstrum[i] = in_cepstrum[i] * weights_vector[i]; + } + return; +} + +void rta_lifter_cepstrum_in_place(rta_real_t * cepstrum, const rta_real_t * weights_vector, + const unsigned int cepstrum_order) +{ + int i; + for(i=0; i<cepstrum_order; i++) + { + cepstrum[i] *= weights_vector[i]; + } + return; +} + +void rta_lifter_cepstrum_stride(rta_real_t * out_cepstrum, const int o_stride, + rta_real_t * in_cepstrum, const int i_stride, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int cepstrum_order) +{ + int ii, io, iw; + for(ii=0, io=0, iw=0; + ii<cepstrum_order*i_stride; + ii+=i_stride, io+=o_stride, iw+=w_stride) + { + out_cepstrum[io] = in_cepstrum[ii] * weights_vector[iw]; + } + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lifter.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lifter.h new file mode 100644 index 0000000000000000000000000000000000000000..e373d0518c1b8854d9e02596735e87b21a4725d7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lifter.h @@ -0,0 +1,190 @@ +/** + * @file rta_lifter.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Cepstral liftering (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * @see http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_LIFTER_H_ +#define _RTA_LIFTER_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + rta_lifter_mode_normal = 0, /**< default */ + rta_lifter_mode_inverse = 1 /**< to undo a normal liftering */ +} rta_lifter_mode_t; + +typedef enum +{ + rta_lifter_exponential = 0, /**< default, Auditory Toolbox like */ + rta_lifter_sinusoidal = 1 /**< HTK like */ +} rta_lifter_t; + + +/* from lifter.m */ +/** + * Generate a vector of weights 'weights_vector' to lifter a cepstrum + * (usually to boost high coefficients). First coefficient is unchanged. + * + * 'factor' = exponent of x i^n liftering in exponential type + * (Auditory toolbox like) + * 'factor' = length of sin-curve liftering in sinusoidal mode (HTK style) + * + * @param weights_vector size is 'cepstrum_order' + * @param cepstrum_order number of input and output cepstrum coefficients + * @param liftering_factor + * 'lifter_t' == exponential_lifter: + * 0. is neutral, 0.6 is usual + * 'lifter_t' == sinusoidal_lifter: + * 'liftering_factor' must be >0. + * 1. is neutral, 22. is usual + * @param lifter_t + * 'lifter_t' == exponential_lifter: Auditory Toolbox like + * 'lifter_t' == sinusoidal_lifter: HTK like + * @param lifter_m + * 'lifter_m' == rta_lifter_mode_normal: standard calculation, the one you + * want to + * 'lifter_m' == rta_lifter_mode_inverse: inverse calculation, to undo a + * liftering. + * + * @return 1 on success 0 on fail + */ +int rta_lifter_weights(rta_real_t * weights_vector, + const unsigned int cepstrum_order, + const rta_real_t liftering_factor, + const rta_lifter_t lifter_t, + const rta_lifter_mode_t lifter_m); + + +/** + * Generate a vector of weights 'weights_vector' to lifter a cepstrum + * (usually to boost high coefficients). First coefficient is unchanged. + * + * 'factor' = exponent of x i^n liftering in exponential type + * (Auditory toolbox like) + * 'factor' = length of sin-curve liftering in sinusoidal mode (HTK style) + * + * @param weights_vector size is 'cepstrum_order' + * @param w_stride is 'weights_vector' stride + * @param cepstrum_order number of input and output cepstrum coefficients + * @param liftering_factor + * 'lifter_t' == exponential_lifter: + * 0. is neutral, 0.6 is usual + * 'lifter_t' == sinusoidal_lifter: + * 'liftering_factor' must be >0. + * 1. is neutral, 22. is usual + * @param lifter_t + * 'lifter_t' == exponential_lifter: Auditory Toolbox like + * 'lifter_t' == sinusoidal_lifter: HTK like + * @param lifter_m + * 'lifter_m' == rta_lifter_mode_normal: standard calculation, the one you + * want to + * 'lifter_m' == rta_lifter_mode_inverse: inverse calculation, to undo a + * liftering. + * + * @return 1 on success 0 on fail + */ +int rta_lifter_weights_stride( + rta_real_t * weights_vector, const int w_stride, + const unsigned int cepstrum_order, + const rta_real_t liftering_factor, + const rta_lifter_t lifter_t, const rta_lifter_mode_t lifter_m); + + +/** + * Apply lifter to 'cepstrum' as + * 'out_cepstrum' = 'in_cepstrum'*'weights_vector' + * + * This can be in place calculation if 'out_cepstrum' == 'in_cepstrum' + * + * @param out_cepstrum size is 'cepstrum_order' + * @param in_cepstrum size is 'cepstrum_order' + * @param weights_vector size is 'cepstrum_order' + * @param cepstrum_order number of input and output cepstrum coefficients + */ +void rta_lifter_cepstrum(rta_real_t * out_cepstrum, rta_real_t * in_cepstrum, + const rta_real_t * weights_vector, + const unsigned int cepstrum_order); + +/** + * Apply lifter to 'cepstrum' as + * 'cepstrum' = 'cepstrum'*'weights_vector' + * + * This is in place calculation. + * + * @param cepstrum size is 'cepstrum_order' + * @param weights_vector size is 'cepstrum_order' + * @param cepstrum_order number of input and output cepstrum coefficients + */ +void rta_lifter_cepstrum_in_place( + rta_real_t * cepstrum, const rta_real_t * weights_vector, + const unsigned int cepstrum_order); + +/** + * Apply lifter to 'cepstrum' as + * 'cepstrum' = 'cepstrum'*'weights_vector' + * + * This can be in place calculation if 'out_cepstrum' == 'in_cepstrum' + * and 'i_stride' == 'o_stride'. + * + * @param out_cepstrum size is 'cepstrum_order' + * @param o_stride is 'out_cepstrum' stride + * @param in_cepstrum size is 'cepstrum_order' + * @param i_stride is 'in_cepstrum' stride + * @param weights_vector size is 'cepstrum_order' + * @param w_stride is 'weights_vector' stride + * @param cepstrum_order number of input and output cepstrum coefficients + * + */ +void rta_lifter_cepstrum_stride( + rta_real_t * out_cepstrum, const int o_stride, + rta_real_t * in_cepstrum, const int i_stride, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int cepstrum_order); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_LIFTER_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lpc.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lpc.c new file mode 100644 index 0000000000000000000000000000000000000000..d5abd2e02071b73c33583bc92f9e347b5063d61f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lpc.c @@ -0,0 +1,209 @@ +/** + * @file rta_lpc.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 27 12:25:16 2007 + * + * @brief Linear Prediction Coding (Autocorrelation - Durbin-Levinson method) + * + * Based on mat_mtl (used in super_vp) by Axel Roebel + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_lpc.h" + +#include "rta_float.h" +#include "rta_math.h" + +#include "rta_correlation.h" + +/* Requirements: input_size >= lpc_size > 1 */ +/* autocorrelation_size >= input_size - lpc_size */ +/* Note: lpc_size == lpc_order+1 */ +void rta_lpc(rta_real_t * lpc, const unsigned int lpc_size, + rta_real_t * error, rta_real_t * autocorrelation, + const rta_real_t * input_vector, const unsigned int input_size) +{ + /* Requirement: (a_size, b_size) >= c_size + lpc_order */ + rta_correlation_raw(autocorrelation, lpc_size, + input_vector, input_vector, input_size); + /* Requirement: a_size >= lpc_size */ + rta_levinson(lpc, lpc_size, error, autocorrelation); + + return; +} + +/* Requirements: input_size >= lpc_size > 1 */ +/* autocorrelation_size >= input_size - lpc_size */ +/* Note: lpc_size == lpc_order+1 */ +void rta_lpc_stride( + rta_real_t * lpc, const int l_stride, const unsigned int lpc_size, + rta_real_t * error, + rta_real_t * autocorrelation, const int a_stride, + const rta_real_t * input_vector, const int i_stride, + const unsigned int input_size) +{ + /* Requirement: (a_size, b_size) >= c_size + lpc_size */ + rta_correlation_raw_stride(autocorrelation, a_stride, lpc_size, + input_vector, i_stride, input_vector, i_stride, + input_size); + /* Requirement: a_size >= lpc_size */ + rta_levinson_stride(lpc, l_stride, lpc_size, error, autocorrelation, a_stride); + + return; +} + + +/* Requirement: a_size >= l_size > 1 */ +void rta_levinson( + rta_real_t * levinson, const unsigned int l_size, rta_real_t * error, + const rta_real_t * autocorrelation) +{ + int i,j,k; + + levinson[0] = 1.; + if(rta_abs(autocorrelation[0]) <= RTA_REAL_MIN) + { + for(i=1; i<l_size; i++) + { + levinson[i] = 0.; + } + *error = 0.; + } + else + { + /* skip first coefficient, which value is 1. anyway */ + rta_real_t * lev1 = levinson+1; + rta_real_t tmp_sum; + rta_real_t reflexion; + + lev1[0] = -autocorrelation[1] / autocorrelation[0]; + *error = autocorrelation[0] + lev1[0] * autocorrelation[1]; + + for(i=1; i<l_size-1; i++) + { + /* No more error (constant signal?), just fill with zeroes */ + if(rta_abs(*error) <= RTA_REAL_MIN) + { + for(; i<l_size-1; i++) + { + lev1[i] = 0.; + } + break; + } + + tmp_sum = autocorrelation[i+1]; + for(j=0; j<i; j++) + { + tmp_sum += lev1[j] * autocorrelation[i-j]; + } + + lev1[i] = reflexion = -tmp_sum / *error; + *error += tmp_sum * reflexion; + + for(j=0, k=i-j-1; j<k; ++j, --k) + { + const rta_real_t tmp = lev1[j]; + lev1[j] += reflexion*lev1[k]; + lev1[k] += reflexion*tmp; + } + + if (k==j) + { + lev1[k] += reflexion*lev1[k]; + } + } + } + return; +} + +/* Requirement: a_size*a_stride >= l_size*l_stride > 1 */ +void rta_levinson_stride(rta_real_t * levinson, const int l_stride, + const unsigned int l_size, rta_real_t * error, + const rta_real_t * autocorrelation, const int a_stride) +{ + int i,j,k; + + levinson[0] = 1.; + if(rta_abs(autocorrelation[0]) <= RTA_REAL_MIN) + { + for(i=l_stride; i<l_size*l_stride; i+=l_stride) + { + levinson[i] = 0.; + } + *error = 0.; + } + else + { + /* skip first coefficient, which value is 1. anyway */ + rta_real_t * lev1 = levinson+l_stride; + rta_real_t tmp_sum; + rta_real_t reflexion; + + lev1[0] = -autocorrelation[a_stride] / autocorrelation[0]; + *error = autocorrelation[0] + lev1[0] * autocorrelation[a_stride]; + + for(i=1; i<l_size-1; i++) + { + /* No more error (constant signal?), just fill with zeroes */ + if(rta_abs(*error) <= RTA_REAL_MIN) + { + for(; i<l_size-1; i++) + { + lev1[i*l_stride] = 0.; + } + break; + } + + tmp_sum = autocorrelation[(i+1)*a_stride]; + for(j=0; j<i; j++) + { + tmp_sum += lev1[j*l_stride] * autocorrelation[(i-j)*a_stride]; + } + + lev1[i*l_stride] = reflexion = -tmp_sum / *error; + *error += tmp_sum * reflexion; + + for(j=0, k=i-j-1; j<k; ++j, --k) + { + const rta_real_t tmp = lev1[j*l_stride]; + lev1[j*l_stride] += reflexion*lev1[k*l_stride]; + lev1[k*l_stride] += reflexion*tmp; + } + + if (k==j) + { + lev1[k*l_stride] += reflexion*lev1[k*l_stride]; + } + } + } + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lpc.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lpc.h new file mode 100644 index 0000000000000000000000000000000000000000..efde5eef4c4e1dc308c1e2534f8120512dc3c15d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_lpc.h @@ -0,0 +1,173 @@ +/** + * @file rta_lpc.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 27 12:25:16 2007 + * + * @brief Linear Prediction Coding (Autocorrelation - Durbin-Levinson method) + * + * Based on mat_mtl (used in super_vp) by Axel Roebel + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_LPC_H_ +#define _RTA_LPC_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Calculate the linear prediction coefficients 'lpc' of order + * 'lpc_size'-1 for 'input_vector', using autocorrelation and + * levinson-durbin decomposition + * + * Calculate the linear prediction coefficients L of order N + * for the given input vector X such that + * + * sum(X(n-k)*L(k)) =! min + * + * \see rta_correlation_raw + * \see rta_levinson + * + * @param lpc coefficients vector + * @param lpc_size is lpc order + 1 and must be > 0 + * @param error is the prediction error (variance) + * @param autocorrelation size must be >= 'lpc_size'. It + * is computed within this function + * @param input_vector size is 'input_size' + * @param input_size must be >= lpc_size + */ +void +rta_lpc(rta_real_t * lpc, const unsigned int lpc_size, + rta_real_t * error, rta_real_t * autocorrelation, + const rta_real_t * input_vector, const unsigned int input_size); + +/** + * Calculate the linear prediction coefficients 'lpc' of order + * 'lpc_size'-1 for 'input_vector', using autocorrelation and + * levinson-durbin decomposition + * + * Calculate the linear prediction coefficients L of order N + * for the given input vector X such that + * + * sum(X(n-k)*L(k)) =! min + * + * \see rta_correlation_raw_stride + * \see rta_levinson_stride + * + * @param lpc coefficients vector + * @param l_stride is 'lpc' vector stride + * @param lpc_size is lpc order + 1 and must be > 0 + * @param error is the prediction error (variance) + * @param autocorrelation size must be >= 'lpc_size'. It + * is computed within this function + * @param a_stride is 'autocorrelation' vector stride + * @param input_vector size is 'input_size' + * @param i_stride is 'input_vector' stride + * @param input_size must be >= lpc_size + */ +void +rta_lpc_stride(rta_real_t * lpc, const int l_stride, const unsigned int lpc_size, + rta_real_t * error, + rta_real_t * autocorrelation, const int a_stride, + const rta_real_t * input_vector, const int i_stride, + const unsigned int input_size); + +/** + * Levinson-Durbin decomposition. + * + * the levinson function calculates the vector L + * that solves the linear equation + * + * [ A(1) A(2) ... A(N) ] [ L(2) ] = [ -A(2) ] + * [ A(2) A(1) ... A(N-1) ] [ L(3) ] = [ -A(3) ] + * [ . . . ] [ . ] = [ . ] + * [ A(N-1) A(N-2) ... A(2) ] [ L(N) ] = [ -A(N) ] + * [ A(N) A(N-1) ... A(1) ] [ L(N+1) ] = [ -A(N+1) ] + * + * The coefficient vector L will have N+1 elements with the first element + * set to 1. The form of the equation is adapted to solve the + * linear prediction problem + * + * sum(X(n-k)*L(k)) = min + * + * where A is the autocorrelation sequence of X + * + * @param levinson coefficients vector + * @param l_size is levinson order + 1 and must be > 1 + * @param error is the prediction error (variance) + * @param autocorrelation vector is given and its size must be >= 'l_size' + */ +void +rta_levinson(rta_real_t * levinson, const unsigned int l_size, rta_real_t * error, + const rta_real_t * autocorrelation); + +/** + * Levinson-Durbin decomposition. + * + * the levinson function calculates the vector L + * that solves the linear equation + * + * [ A(1) A(2) ... A(N) ] [ L(2) ] = [ -A(2) ] + * [ A(2) A(1) ... A(N-1) ] [ L(3) ] = [ -A(3) ] + * [ . . . ] [ . ] = [ . ] + * [ A(N-1) A(N-2) ... A(2) ] [ L(N) ] = [ -A(N) ] + * [ A(N) A(N-1) ... A(1) ] [ L(N+1) ] = [ -A(N+1) ] + * + * The coefficient vector L will have N+1 elements with the first element + * set to 1. The form of the equation is adapted to solve the + * linear prediction problem + * + * sum(X(n-k)*L(k)) = min + * + * where A is the autocorrelation sequence of X + * + * @param levinson coefficients vector + * @param l_stride is 'levinson' vector stride + * @param l_size is levinson order + 1 and must be > 1 + * @param error is the prediction error (variance) + * @param autocorrelation vector is given and its size must be >= 'l_size' + * @param a_stride is 'autocorrelation' stride + */ +void +rta_levinson_stride(rta_real_t * levinson, const int l_stride, + const unsigned int l_size, rta_real_t * error, + const rta_real_t * autocorrelation, const int a_stride); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_LPC_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mean_variance.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mean_variance.c new file mode 100644 index 0000000000000000000000000000000000000000..9d6bcc0c149a5cc8bbadad6515a598790c034748 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mean_variance.c @@ -0,0 +1,309 @@ +/** + * @file rta_mean_variance.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 25 16:13:42 2008 + * + * @brief Mean and variance from an input vector + * + * @copyright + * Copyright (C) 2008 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_mean_variance.h" + +/* Var(X) = E((X-mu)^2) = E(X^2) - mu^2 */ +void +rta_mean_variance(rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const unsigned int i_size) + +{ + unsigned int i; + + rta_real_t mean_x2 = 0.; /* mean(x^2) */ + rta_real_t mean2; /* mean^2 */ + const rta_real_t normalisation_factor = 1. / (rta_real_t) i_size; + + *mean = 0.; + + for(i=0; i<i_size; i++) + { + *mean += input[i]; + mean_x2 += input[i] * input[i]; + } + + *mean *= normalisation_factor; + mean_x2 *= normalisation_factor; + mean2 = *mean * *mean; + + if(mean_x2 > mean2) + { + *variance = mean_x2 - mean2; + } + else /* roundoff errors */ + { + *variance = 0.; + } + + return; +} + +/* Var(X) = E((X-mu)^2) = E(X^2) - mu^2 */ +void +rta_mean_variance_stride(rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const int i_stride, + const unsigned int i_size) + +{ + unsigned int i; + + rta_real_t mean_x2 = 0.; /* mean(x^2) */ + rta_real_t mean2; /* mean^2 */ + const rta_real_t normalisation_factor = 1. / (rta_real_t) i_size; + + *mean = 0.; + + for(i=0; i<i_size*i_stride; i+=i_stride) + { + *mean += input[i]; + mean_x2 += input[i] * input[i]; + } + + *mean *= normalisation_factor; + mean_x2 *= normalisation_factor; + mean2 = *mean * *mean; + + if(mean_x2 > mean2) + { + *variance = mean_x2 - mean2; + } + else /* roundoff errors */ + { + *variance = 0.; + } + + return; +} + +void +rta_mean_variance_unbiased(rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const unsigned int i_size) + +{ + unsigned int i; + + rta_real_t mean_x2 = 0.; /* mean(x^2) */ + rta_real_t mean2; /* mean^2 */ + const rta_real_t mean_norm_factor = 1. / (rta_real_t) i_size; + rta_real_t var_norm_factor; + + if(i_size > 1) + { + var_norm_factor = 1. / (rta_real_t) (i_size - 1); + } + else + { + var_norm_factor = 1.; + } + + *mean = 0.; + + for(i=0; i<i_size; i++) + { + *mean += input[i]; + mean_x2 += input[i] * input[i]; + } + + *mean *= mean_norm_factor; + mean2 = *mean * *mean; + + if(mean_x2 > mean2) + { + *variance = (mean_x2 - i_size * mean2) * var_norm_factor; + } + else /* roundoff errors */ + { + *variance = 0.; + } + + return; +} + +void +rta_mean_variance_unbiased_stride(rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const int i_stride, + const unsigned int i_size) + +{ + unsigned int i; + + rta_real_t mean_x2 = 0.; /* mean(x^2) */ + rta_real_t mean2; /* mean^2 */ + const rta_real_t mean_norm_factor = 1. / (rta_real_t) i_size; + rta_real_t var_norm_factor; + + if(i_size > 1) + { + var_norm_factor = 1. / (rta_real_t) (i_size - 1); + } + else + { + var_norm_factor = 1.; + } + + *mean = 0.; + + for(i=0; i<i_size*i_stride; i+=i_stride) + { + *mean += input[i]; + mean_x2 += input[i] * input[i]; + } + + *mean *= mean_norm_factor; + mean2 = *mean * *mean; + + if(mean_x2 > mean2) + { + *variance = (mean_x2 - i_size * mean2) * var_norm_factor; + } + else /* roundoff errors */ + { + *variance = 0.; + } + + return; +} + +rta_real_t rta_mean(rta_real_t * input, const unsigned int i_size) +{ + rta_real_t mean = 0.; + unsigned int i; + + for(i = 0; i<i_size; i++) + { + mean += input[i]; + } + + mean /= (rta_real_t) i_size; + + return mean; +} + +rta_real_t rta_mean_stride(rta_real_t * input, const int i_stride, + const unsigned int i_size) +{ + rta_real_t mean = 0.; + unsigned int i; + + for(i = 0; i<i_size*i_stride; i+=i_stride) + { + mean += input[i]; + } + + mean /= (rta_real_t) i_size; + + return mean; +} + +rta_real_t rta_variance(rta_real_t * input, const unsigned int i_size, + rta_real_t mean) +{ + rta_real_t variance = 0.; + unsigned int i; + + for(i=0; i<i_size; i++) + { + rta_real_t t = input[i] - mean; + variance += t * t; + } + + variance /= (rta_real_t) i_size; + + return variance; +} + +rta_real_t rta_variance_stride(rta_real_t * input, const int i_stride, + const unsigned int i_size, + rta_real_t mean) +{ + rta_real_t variance = 0.; + unsigned int i; + + for(i=0; i<i_size*i_stride; i+=i_stride) + { + rta_real_t t = input[i] - mean; + variance += t * t; + } + + variance /= (rta_real_t) i_size; + + return variance; +} + +rta_real_t +rta_variance_unbiased(rta_real_t * input, const unsigned int i_size, + rta_real_t mean) +{ + rta_real_t variance = 0.; + unsigned int i; + + for(i=0; i<i_size; i++) + { + rta_real_t t = input[i] - mean; + variance += t * t; + } + + if(i_size > 1) + { + variance /= (rta_real_t) (i_size - 1); + } + + return variance; +} + +rta_real_t +rta_variance_unbiased_stride(rta_real_t * input, const int i_stride, + const unsigned int i_size, rta_real_t mean) +{ + rta_real_t variance = 0.; + unsigned int i; + + for(i=0; i<i_size*i_stride; i+=i_stride) + { + rta_real_t t = input[i] - mean; + variance += t * t; + } + + if(i_size > 1) + { + variance /= (rta_real_t) (i_size - 1); + } + + return variance; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mean_variance.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mean_variance.h new file mode 100644 index 0000000000000000000000000000000000000000..8df0a414eb9ac8cce1da289d47d9864b0725b932 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mean_variance.h @@ -0,0 +1,219 @@ +/** + * @file rta_mean_variance.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 25 16:13:42 2008 + * + * @brief Mean and variance from an input vector + * + * @copyright + * Copyright (C) 2008 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_MEAN_VARIANCE_H_ +#define _RTA_MEAN_VARIANCE_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Variance is computed as var(x) = E(x^2) - mean(x)^2 so as it is + * done in one loop. Note that this may lead to inacuracies when + * E(x^2) and mean(x)^2 are similar in magnitude. The mean and + * variance are normalised by 'i_size', hence the bias. + * \see rta_variance + * \see rta_mean_variance_unbiased + * + * @param mean is a pointer to the mean result + * @param variance is a pointer to the variance result + * @param input is the input vector of size 'i_size' + * @param i_size is the size of 'input' and must be > 0 + */ +void +rta_mean_variance(rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const unsigned int i_size); + +/** + * Variance is computed as var(x) = E(x^2) - mean(x)^2 so as it is + * done in one loop. Note that this may lead to inacuracies when + * E(x^2) and mean(x)^2 are similar in magnitude. The mean and + * variance are normalised by 'i_size', hence the bias. + * \see rta_variance + * \see rta_mean_variance_unbiased + * + * @param mean is a pointer to the mean result + * @param variance is a pointer to the variance result + * @param input is the input vector of size 'i_size' + * @param i_stride is the 'input' stride + * @param i_size is the size of 'input' and must be > 0 + */ +void +rta_mean_variance_stride( + rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const int i_stride, const unsigned int i_size); + +/** + * Variance is computed as var(x) = E(x^2) - mean(x)^2 so as it is + * done in one loop. Note that this may lead to inacuracies when + * E(x^2) and mean(x)^2 are similar in magnitude. The mean and + * variance are normalised by ('i_size' - 1). + * \see rta_variance + * \see rta_mean_variance + * + * @param mean is a pointer to the mean result + * @param variance is a pointer to the variance result + * @param input is the input vector of size 'i_size' + * @param i_size is the size of 'input' and must be > 0 + */ +void +rta_mean_variance_unbiased(rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const unsigned int i_size); + +/** + * Variance is computed as var(x) = E(x^2) - mean(x)^2 so as it is + * done in one loop. Note that this may lead to inacuracies when + * E(x^2) and mean(x)^2 are similar in magnitude. The mean and + * variance are normalised by ('i_size' - 1). + * \see rta_variance + * \see rta_mean_variance + * + * @param mean is a pointer to the mean result + * @param variance is a pointer to the variance result + * @param input is the input vector of size 'i_size' + * @param i_stride is the 'input' stride + * @param i_size is the size of 'input' and must be > 0 + */ +void +rta_mean_variance_unbiased_stride( + rta_real_t * mean, rta_real_t * variance, + rta_real_t * input, const int i_stride, const unsigned int i_size); + +/** + * Mean of 'input' + * + * @param input is the input vector of size 'i_size' + * @param i_size is the size of 'input' and must be > 0 + * + * @return mean of 'input' + */ +rta_real_t +rta_mean(rta_real_t * input, const unsigned int i_size); + +/** + * Mean of 'input' + * + * @param input is the input vector of size 'i_size' + * @param i_stride is the 'input' stride + * @param i_size is the size of 'input' and must be > 0 + * + * @return mean of 'input' + */ +rta_real_t +rta_mean_stride( + rta_real_t * input, const int i_stride, const unsigned int i_size); + +/** + * Variance is computed as var(x) = E( (x - mean(x))^2 ) and is + * normalised by 'i_size', hence the bias. + * \see rta_variance_unbiased + * \see rta_mean_variance + * \see rta_mean + * + * @param input is the input vector of size 'i_size' + * @param i_size is the size of 'input' and must be > 0 + * @param mean is the mean of 'input' + * + * @return variance of 'input' + */ +rta_real_t +rta_variance(rta_real_t * input, const unsigned int i_size, rta_real_t mean); + +/** + * Variance is computed as var(x) = E( (x - mean(x))^2 ) and is + * normalised by 'i_size', hence the bias. + * \see rta_variance_unbiased + * \see rta_mean_variance + * \see rta_mean + * + * @param input is the input vector of size 'i_size' + * @param i_stride is the 'input' stride + * @param i_size is the size of 'input' and must be > 0 + * @param mean is the mean of 'input' + * + * @return variance of 'input' + */ +rta_real_t +rta_variance_stride( + rta_real_t * input, const int i_stride, const unsigned int i_size, + rta_real_t mean); + +/** + * Variance is computed as var(x) = E( (x - mean(x))^2 ) and is + * normalised by ('i_size' - 1). + * \see rta_variance + * \see rta_mean_variance + * \see rta_mean + * + * @param input is the input vector of size 'i_size' + * @param i_size is the size of 'input' and must be > 0 + * @param mean is the mean of 'input' + * + * @return variance of 'input' + */ +rta_real_t +rta_variance_unbiased(rta_real_t * input, const unsigned int i_size, + rta_real_t mean); + +/** + * Variance is computed as var(x) = E( (x - mean(x))^2 ) and is + * normalised by ('i_size' - 1). + * \see rta_variance + * \see rta_mean_variance + * \see rta_mean + * + * @param input is the input vector of size 'i_size' + * @param i_stride is the 'input' stride + * @param i_size is the size of 'input' and must be > 0 + * @param mean is the mean of 'input' + * + * @return variance of 'input' + */ +rta_real_t rta_variance_unbiased_stride( + rta_real_t * input, const int i_stride, const unsigned int i_size, + rta_real_t mean); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_MEAN_VARIANCE_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mel.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mel.c new file mode 100644 index 0000000000000000000000000000000000000000..fba49002db27b29799c155e027417cc4e0051131 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mel.c @@ -0,0 +1,113 @@ +/** + * @file rta_mel.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Mel conversions (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * @see http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_mel.h" +#include "rta_math.h" + +/*@{ Constants for Slaney's Mel conversion (Auditory Toolbox) */ +static const rta_real_t rta_slaney_mel_min_freq = 0. ; + +/** 200. / 3. size of lower bands */ +static const rta_real_t rta_slaney_mel_linear_bandwidth = 66.6666666666666666667; + +static const rta_real_t rta_slaney_mel_break_freq_in_hz = 1000.; + +/** + * starting mel value for log region + * (rta_slaney_mel_break_freq_in_hz - rta_slaney_mel_min_freq) /rta_slaney_mel_linear_bandwidth; + */ +static const rta_real_t rta_slaney_mel_break_freq_in_mel = 15.; + +/** + * logstep = exp(log(6.4)/27); + * the magic 1.0711703 which is the ratio needed to get from 1000 + * Hz to 6400 Hz in 27 steps, and is *almost* the ratio between + * 1000 Hz and the preceding linear filter center at 933.33333 Hz + * (actually 1000/933.33333 = 1.07142857142857 and + * exp(log(6.4)/27) = 1.07117028749447) + * + * mel_step = log(logstep) + * log(6.4)/ 27. + */ +static const rta_real_t rta_slaney_mel_step = 6.87517774209491228099e-02; +/*@} */ + +rta_real_t rta_hz_to_mel_slaney(rta_real_t freq_in_hz) +{ + rta_real_t freq_in_mel = 0.; + if(freq_in_hz < rta_slaney_mel_break_freq_in_hz) + { + freq_in_mel = (freq_in_hz - rta_slaney_mel_min_freq) / rta_slaney_mel_linear_bandwidth; + } + else + { + freq_in_mel = rta_slaney_mel_break_freq_in_mel + + rta_log(freq_in_hz / rta_slaney_mel_break_freq_in_hz) / rta_slaney_mel_step; + } + return freq_in_mel; +} + +rta_real_t rta_hz_to_mel_htk(rta_real_t freq_in_hz) +{ + return 2595. * rta_log10(1. + freq_in_hz/700.); +} + + + +rta_real_t rta_mel_to_hz_slaney(rta_real_t freq_in_mel) +{ + rta_real_t freq_in_hz = 0.; + if(freq_in_mel < rta_slaney_mel_break_freq_in_mel) + { + freq_in_hz = rta_slaney_mel_min_freq + rta_slaney_mel_linear_bandwidth * freq_in_mel; + } + else + { + freq_in_hz = rta_slaney_mel_break_freq_in_hz * rta_exp( + rta_slaney_mel_step * (freq_in_mel - rta_slaney_mel_break_freq_in_mel)); + } + return freq_in_hz; +} + +rta_real_t rta_mel_to_hz_htk(rta_real_t freq_in_mel) +{ + return 700. * ( rta_pow(10, freq_in_mel / 2595.) -1. ); +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mel.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mel.h new file mode 100644 index 0000000000000000000000000000000000000000..5aff16fce9f671ce828a278b1b96d7cc8b1eeae5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_mel.h @@ -0,0 +1,124 @@ +/** + * @file rta_mel.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Mel conversions (HTK and Auditory Toolbox styles) + * + * Based on Rastamat by Dan Ellis. + * @see http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_MEL_H_ +#define _RTA_MEL_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum +{ + rta_mel_slaney = 1, /**< Slaney-style mel is scaled to be approx + * constant E per channel */ + rta_mel_htk = 2 /**< HTK-style is constant max amplitude per + * channel */ +} rta_mel_t; + + +/** MEL from melfcc.m */ + +/** from hz2mel.m */ +/** + * function pointer to avoid tests during conversions + * rta_real_t parameter in frequency in Hertz + * rta_real_t return is corresponding mel value + */ +typedef rta_real_t (*rta_hz_to_mel_function) (rta_real_t); + +/** + * Convert frequencies f (in Hz) to mel 'scale'. + * Mel fn to match Slaney's Auditory Toolbox mfcc.m + * + * @param freq_in_hz [0.,22050.] + * + * @return corresponding mel value [0.,60.] + */ +rta_real_t rta_hz_to_mel_slaney(rta_real_t freq_in_hz); + +/** + * Convert frequencies f (in Hz) to mel 'scale'. + * uses the mel axis defined in the htk_book + * + * @param freq_in_hz [0.,22050.] + * + * @return corresponding mel value [0.,3923.] + */ +rta_real_t rta_hz_to_mel_htk(rta_real_t freq_in_hz); + +/** from mel2hz.m */ +/** + * function pointer to avoid tests during conversions + * rta_real_t parameter is mel value + * rta_real_t return is corresponding frequency + */ +typedef rta_real_t (*rta_mel_to_hz_function) (rta_real_t); + +/** + * Convert 'mel scale' frequencies into Hz + * use the formula from Slaney's mfcc.m + * + * @param freq_in_mel [0.,60.] + * + * @return corresponding frequency [0.,22050.] + */ +rta_real_t rta_mel_to_hz_slaney(rta_real_t freq_in_mel); + +/** + * Convert 'mel scale' frequencies into Hz + * use the HTK formula + * + * @param freq_in_mel [0.,3923.] + * + * @return corresponding frequency [0.,22050.] + */ +rta_real_t rta_mel_to_hz_htk(rta_real_t freq_in_mel); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_MEL_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_moments.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_moments.c new file mode 100644 index 0000000000000000000000000000000000000000..89a90f4c8bca001b21bb532f5f23e5295b1da3e7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_moments.c @@ -0,0 +1,324 @@ +/** + * @file rta_moments.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Thu Dec 13 15:28:26 2007 + * + * @brief Statistical moments functions + * + * The moments are calculated over the indexes and weighted by the + * input values (eg. the amplitudes of the spectrum regularly + * sampled). Note that all moments (but the first) are centered. The + * results unit is index (starting from 0). + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_moments.h" +#include "rta_math.h" + +/* 1st order weighted moment over indexes: weighted mean, centroid */ +rta_real_t rta_weighted_moment_1_indexes( + rta_real_t * input_sum, + const rta_real_t * input, const unsigned int input_size) +{ + unsigned int i; + rta_real_t centroid = 0.; + *input_sum = 0.; + + for(i=0; i<input_size; i++) + { + centroid += input[i] * i; + *input_sum += input[i]; + } + + if(*input_sum > 0.) + { + centroid /= *input_sum; + } + else + { + /* flat and null input => centroid is the middle */ + centroid = (input_size - 1) * 0.5; + } + + return centroid; +} + +rta_real_t rta_weighted_moment_1_indexes_stride( + rta_real_t * input_sum, + const rta_real_t * input, const int i_stride, + const unsigned int input_size) +{ + unsigned int i; + int is; + rta_real_t centroid = 0.; + *input_sum = 0.; + + for(i=0, is=0; i<input_size; i++, is+=i_stride) + { + centroid += input[is] * i; + *input_sum += input[is]; + } + + if(*input_sum > 0.) + { + centroid /= *input_sum; + } + else + { + /* flat and null input => centroid is the middle */ + centroid = (input_size - 1) * 0.5; + } + + return centroid; +} + + +/* 2nd order weighted central moment over indexes: spread, weighted variance */ +/* Request: input_sum != 0. */ +/* note: weighted standard deviation is sqrt(weighted variance) */ +rta_real_t rta_weighted_moment_2_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum) +{ + unsigned int i; + rta_real_t moment = 0.; + rta_real_t tmp_diff; + + for(i=0; i<input_size; i++) + { + tmp_diff = i - centroid; + moment += tmp_diff * tmp_diff * input[i]; + } + + return (moment / input_sum); +} + +rta_real_t rta_weighted_moment_2_indexes_stride( + const rta_real_t * input, const int i_stride, + const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum) +{ + unsigned int i; + int is; + rta_real_t moment = 0.; + rta_real_t tmp_diff; + + for(i=0, is=0; i<input_size; i++, is+=i_stride) + { + tmp_diff = i - centroid; + moment += tmp_diff * tmp_diff * input[is]; + } + + return (moment / input_sum); +} + +/* 3rd order weighted central moment over indexes*/ +/* Request: input_sum != 0. */ +rta_real_t rta_weighted_moment_3_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum) +{ + unsigned int i; + rta_real_t moment = 0.; + rta_real_t tmp_diff; + + for(i = 0; i<input_size; i++) + { + tmp_diff = i - centroid; + moment += tmp_diff * tmp_diff * tmp_diff * input[i]; + } + + return (moment / input_sum); +} + +rta_real_t rta_weighted_moment_3_indexes_stride( + const rta_real_t * input, const int i_stride, + const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum) +{ + unsigned int i; + int is; + rta_real_t moment = 0.; + rta_real_t tmp_diff; + + for(i = 0, is=0; i<input_size; i++, is+=i_stride) + { + tmp_diff = i - centroid; + moment += tmp_diff * tmp_diff * tmp_diff * input[is]; + } + + return (moment / input_sum); +} + +/* 3rd order standardised weighted central moment over indexes: skewness */ +/* Requests: input_sum != 0. + deviation != 0. */ +rta_real_t rta_std_weighted_moment_3_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation) +{ + return rta_weighted_moment_3_indexes(input, input_size, centroid, input_sum) / + (deviation * deviation * deviation); +} + +rta_real_t rta_std_weighted_moment_3_indexes_stride( + const rta_real_t * input, const int i_stride, + const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation) +{ + return rta_weighted_moment_3_indexes_stride( + input, i_stride, input_size, centroid, input_sum) / + (deviation * deviation * deviation); +} + +/* 4th order weighted central moment over indexes */ +/* Request: input_sum != 0. */ +rta_real_t rta_weighted_moment_4_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum) +{ + unsigned int i; + rta_real_t moment = 0.; + rta_real_t tmp_diff; + + for(i = 0; i<input_size; i++) + { + tmp_diff = i - centroid; + moment += tmp_diff * tmp_diff * tmp_diff * tmp_diff * input[i]; + } + + return (moment / input_sum); +} + +rta_real_t rta_weighted_moment_4_indexes_stride( + const rta_real_t * input, const int i_stride, + const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum) +{ + unsigned int i; + int is; + rta_real_t moment = 0.; + rta_real_t tmp_diff; + + for(i = 0, is=0; i<input_size; i++, is+=i_stride) + { + tmp_diff = i - centroid; + moment += tmp_diff * tmp_diff * tmp_diff * tmp_diff * input[is]; + } + + return (moment / input_sum); +} + +/* 4th order standardised weighted central moment over indexes: kurtosis */ +/* Requests: input_sum != 0. + deviation != 0. */ +rta_real_t rta_std_weighted_moment_4_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation) +{ + return rta_weighted_moment_4_indexes(input, input_size, centroid, input_sum) / + (deviation * deviation * deviation * deviation); +} + +rta_real_t rta_std_weighted_moment_4_indexes_stride( + const rta_real_t * input, const int i_stride, + const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation) +{ + return rta_weighted_moment_4_indexes_stride( + input, i_stride, input_size, centroid, input_sum) / + (deviation * deviation * deviation * deviation); +} + +/* general order weighted central moment over indexes */ +/* Request: input_sum != 0. */ +rta_real_t rta_weighted_moment_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t order) +{ + unsigned int i; + rta_real_t moment = 0.; + + for(i = 0; i<input_size; i++) + { + moment += rta_pow(i - centroid, order) * input[i]; + } + + return (moment / input_sum); +} + +rta_real_t rta_weighted_moment_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t order) +{ + unsigned int i; + int is; + rta_real_t moment = 0.; + + for(i = 0, is=0; i<input_size; i++, is+=i_stride) + { + moment += rta_pow(i - centroid, order) * input[is]; + } + + return (moment / input_sum); +} + +/* general order standardised weighted central moment over indexes */ +/* Requests: input_sum != 0. + deviation != 0. */ +rta_real_t rta_std_weighted_moment_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation, + const rta_real_t order) +{ + return rta_weighted_moment_indexes( + input, input_size, centroid, input_sum, order) / + rta_pow(deviation, order); +} + +rta_real_t rta_std_weighted_moment_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation, + const rta_real_t order) +{ + return rta_weighted_moment_indexes_stride( + input, i_stride, input_size, centroid, input_sum, order) / + rta_pow(deviation, order); +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_moments.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_moments.h new file mode 100644 index 0000000000000000000000000000000000000000..3c38baf151dbabb7804c1aed743c8420ef55e1d9 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_moments.h @@ -0,0 +1,396 @@ +/** + * @file rta_moments.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Thu Dec 13 15:28:26 2007 + * + * @brief Statistical moments functions + * + * The moments are calculated over the indexes and weighted by the + * input values (eg. the amplitudes of the spectrum regularly + * sampled). Note that all moments (but the first) are centered. The + * results unit is index (starting from 0). + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_MOMENTS_H_ +#define _RTA_MOMENTS_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * First order moment over indexes weighted by 'input' values: + * weighted mean, centroid. + * m1 = centroid = sum(i, i*input(i)) / sum(i, input(i)) + * + * @param input_sum is calculated by the function and may be used for + * higher-order moments. It is the sum of all 'input' values. + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * + * @return the first moment, 0.5 * ('input_size' - 1) if 'input_sum' == 0. + */ +rta_real_t +rta_weighted_moment_1_indexes( + rta_real_t * input_sum, + const rta_real_t * input, const unsigned int input_size); + +/** + * First order moment over indexes weighted by 'input' values: + * weighted mean, centroid. + * m1 = centroid = sum(i, i*input(i)) / sum(i, input(i)) + * + * @param input_sum is calculated by the function and may be used for + * higher-order moments. It is the sum of all 'input' values. + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * + * @return the first moment, 0.5 * ('input_size' - 1) if 'input_sum' == 0. + */ +rta_real_t +rta_weighted_moment_1_indexes_stride( + rta_real_t * input_sum, + const rta_real_t * input, const int i_stride, + const unsigned int input_size); + +/** + * Second order weighted central moment over indexes: spread, weighted + * variance. + * m2 = spread = sum(i,input(i) * (i-centroid)^2) / sum(i, input(i)) + * + * Note that standard deviation is std = sqrt(spread) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * + * @return spread + */ +rta_real_t +rta_weighted_moment_2_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum); + +/** + * Second order weighted central moment over indexes: spread, weighted + * variance. + * m2 = spread = sum(i,input(i) * (i-centroid)^2) / sum(i, input(i)) + * + * Note that standard deviation is std = sqrt(spread) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes_stride + * @param input_sum must be != 0. It is the sum of all 'input' values. + * + * @return spread + */ +rta_real_t +rta_weighted_moment_2_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum); + +/** + * Third order weighted central moment over indexes. + * m3 = sum(i,input(i) * (i-centroid)^3) / sum(i, input(i)) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * + * @return third central moment + */ +rta_real_t +rta_weighted_moment_3_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum); + +/** + * Third order weighted central moment over indexes. + * m3 = sum(i,input(i) * (i-centroid)^3) / sum(i, input(i)) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes_stride + * @param input_sum must be != 0. It is the sum of all 'input' values. + * + * @return third central moment + */ +rta_real_t +rta_weighted_moment_3_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum); + +/** + * Third order standardised weighted central moment over indexes: skewness. + * skewness = m3 / std^3 + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param deviation must be != 0. It is the standard deviation. + * \see rta_weighted_moment_2_indexes + * + * @return skewness + */ +rta_real_t +rta_std_weighted_moment_3_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation); + +/** + * Third order standardised weighted central moment over indexes: skewness. + * skewness = m3 / std^3 + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes_stride + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param deviation must be != 0. It is the standard deviation. + * \see rta_weighted_moment_2_indexes_stride + * + * @return skewness + */ +rta_real_t +rta_std_weighted_moment_3_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation); + +/** + * Fourth order weighted central moment over indexes. + * m4 = sum(i,input(i) * (i-centroid)^4) / sum(i, input(i)) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * + * @return fourth central moment + */ +rta_real_t +rta_weighted_moment_4_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum); + +/** + * Fourth order weighted central moment over indexes. + * m4 = sum(i,input(i) * (i-centroid)^4) / sum(i, input(i)) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes_stride + * @param input_sum must be != 0. It is the sum of all 'input' values. + * + * @return fourth central moment + */ +rta_real_t +rta_weighted_moment_4_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum); + +/** + * Fourth order standardised weighted central moment over indexes: kurtosis. + * kurtosis = m4 / std^4 + * + * Note that the kurtosis is often defined as the fourth cumulant + * divided by the square root of the variance, which gives + * kurtosis = m4 / std^4 - 3. This function does not include the "- 3" + * term. + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param deviation must be != 0. It is the standard deviation. + * \see rta_weighted_moment_2_indexes + * + * @return kurtosis + */ +rta_real_t +rta_std_weighted_moment_4_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation); + +/** + * Fourth order standardised weighted central moment over indexes: kurtosis. + * kurtosis = m4 / std^4 + * + * Note that the kurtosis is often defined as the fourth cumulant + * divided by the square root of the variance, which gives + * kurtosis = m4 / std^4 - 3. This function does not include the "- 3" + * term. + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes_stride + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param deviation must be != 0. It is the standard deviation. + * \see rta_weighted_moment_2_indexes_stride + * + * @return kurtosis + */ +rta_real_t +rta_std_weighted_moment_4_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation); + +/** + * General order weighted central moment over indexes. + * m_order = sum(i,input(i) * (i-centroid)^order) / sum(i, input(i)) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param order is the moment order. + * + * @return moment + */ +rta_real_t +rta_weighted_moment_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t order); + +/** + * General order weighted central moment over indexes. + * m_order = sum(i,input(i) * (i-centroid)^order) / sum(i, input(i)) + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes_stride + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param order is the moment order. + * + * @return moment + */ +rta_real_t +rta_weighted_moment_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t order); + +/** + * General order standardised weighted central moment over indexes. + * m_order / std^order + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param deviation must be != 0. It is the standard deviation. + * \see rta_weighted_moment_2_indexes + * @param order is the moment order. + * + * @return standardised moment + */ +rta_real_t +rta_std_weighted_moment_indexes( + const rta_real_t * input, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation, + const rta_real_t order); + +/** + * General order standardised weighted central moment over indexes. + * m_order / std^order + * + * @param input is usually amplitudes or weights. Each element of + * 'input' must be >=0. + * @param i_stride is 'input' stride + * @param input_size is 'input' size + * @param centroid is the first moment of 'input'. + * \see rta_weighted_moment_1_indexes + * @param input_sum must be != 0. It is the sum of all 'input' values. + * @param deviation must be != 0. It is the standard deviation. + * \see rta_weighted_moment_2_indexes + * @param order is the moment order. + * + * @return standardised moment + */ +rta_real_t +rta_std_weighted_moment_indexes_stride( + const rta_real_t * input, const int i_stride, const unsigned int input_size, + const rta_real_t centroid, const rta_real_t input_sum, + const rta_real_t deviation, + const rta_real_t order); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_MOMENTS_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_onepole.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_onepole.c new file mode 100644 index 0000000000000000000000000000000000000000..1742c27c4589a966f2573357faf182e6a4c06e6a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_onepole.c @@ -0,0 +1,123 @@ +/** + * @file rta_onepole.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Aug 29 12:38:46 2008 + * + * @brief One-pole one-zero filters + * + * Simple low-pass and high-pass filters. + * @see rta_biquad.h + * + * @copyright + * Copyright (C) 2008 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_onepole.h" + +inline rta_real_t rta_onepole_lowpass(const rta_real_t x, const rta_real_t f0, + rta_real_t * state) +{ + *state = x * f0 + *state * (1. - f0); + return *state; +} + +inline rta_real_t rta_onepole_highpass(const rta_real_t x, const rta_real_t f0, + rta_real_t * state) +{ + /* highpass = x - lowpass */ + + rta_real_t y = f0 * x + *state; + *state = (1. - f0) * y; + return (x - y); +} + +void rta_onepole_lowpass_vector( + rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state) +{ + unsigned int i; + + for(i=0; i<x_size; i++) + { + y[i] = rta_onepole_lowpass(x[i], f0, state); + } + + return; +} + +void rta_onepole_lowpass_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state) +{ + int ix, iy; + + for(ix = 0, iy = 0; + ix < x_size*x_stride; + ix += x_stride, iy += y_stride) + { + y[iy] = rta_onepole_lowpass(x[ix], f0, state); + } + + return; +} + +void rta_onepole_highpass_vector( + rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state) +{ + unsigned int i; + + for(i=0; i<x_size; i++) + { + y[i] = rta_onepole_highpass(x[i], f0, state); + } + + return; +} + +void rta_onepole_highpass_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state) +{ + int ix, iy; + + for(ix = 0, iy = 0; + ix < x_size*x_stride; + ix += x_stride, iy += y_stride) + { + y[iy] = rta_onepole_highpass(x[ix], f0, state); + } + + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_onepole.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_onepole.h new file mode 100644 index 0000000000000000000000000000000000000000..266b53927cd35f514efb9efbfa04af7729bee079 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_onepole.h @@ -0,0 +1,163 @@ +/** + * @file rta_onepole.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Aug 29 12:38:46 2008 + * + * @brief One-pole one-zero filters + * + * Simple low-pass and high-pass filters. + * @see rta_biquad.h + * + * @copyright + * Copyright (C) 2008 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_ONEPOLE_H_ +#define _RTA_ONEPOLE_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#define inline +#endif + +/** + * One-pole low-pass filter computed as: + * y(n) = f0 * x(n) - (f0 - 1) * y(n-1) + * \see rta_onepole_highpass + * + * @param x is an input sample + * @param f0 is the cutoff frequency, normalised by the nyquist frequency. + * @param state is the one sample delay state. It can be initialised + * with 0. or the last computed value, which is updated by this + * function. + * + * @return the output sample y + */ +inline rta_real_t rta_onepole_lowpass(rta_real_t x, const rta_real_t f0, + rta_real_t * state); + +/** + * One-pole high-pass filter computed as the difference between the + * input and a low-pass filtered input: + * y(n) = x(n) - ( f0 * x(n) - (f0 - 1) * y(n-1) ) + * \see rta_onepole_lowpass + * + * @param x is an input sample + * @param f0 is the cutoff frequency, normalised by the nyquist frequency. + * @param state is the one sample delay state. It can be initialised + * with 0. or the last computed value, which is updated by this + * function. + * + * @return the output sample y + */ +inline rta_real_t rta_onepole_highpass(rta_real_t x, const rta_real_t f0, + rta_real_t * state); +/** + * One-pole low-pass computation on a vector of samples. + * \see rta_onepole_lowpass + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_size is the size of 'y' and 'x' + * @param f0 is the cutoff frequency, normalised by the nyquist frequency. + * @param state is the one sample delay state. It can be initialised + * with 0. or the last computed value, which is updated by this + * function. + */ +void rta_onepole_lowpass_vector( + rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state); + +/** + * One-pole low-pass computation on a vector of samples. + * \see rta_onepole_lowpass + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param y_stride is 'y' stride + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_stride is 'x' stride + * @param x_size is the size of 'y' and 'x' + * @param f0 is the cutoff frequency, normalised by the nyquist frequency. + * @param state is the one sample delay state. It can be initialised + * with 0. or the last computed value, which is updated by this + * function. + */ +void rta_onepole_lowpass_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state); + +/** + * One-pole high-pass computation on a vector of samples. + * \see rta_onepole_highpass + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_size is the size of 'y' and 'x' + * @param f0 is the cutoff frequency, normalised by the nyquist frequency. + * @param state is the one sample delay state. It can be initialised + * with 0. or the last computed value, which is updated by this + * function. + */ +void rta_onepole_highpass_vector( + rta_real_t * y, + const rta_real_t * x, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state); + +/** + * One-pole high-pass computation on a vector of samples. + * \see rta_onepole_highpass + * + * @param y is a vector of output samples. Its size is 'x_size' + * @param y_stride is 'y' stride + * @param x is a vector of input samples. Its size is 'x_size' + * @param x_stride is 'x' stride + * @param x_size is the size of 'y' and 'x' + * @param f0 is the cutoff frequency, normalised by the nyquist frequency. + * @param state is the one sample delay state. It can be initialised + * with 0. or the last computed value, which is updated by this + * function. + */ +void rta_onepole_highpass_vector_stride( + rta_real_t * y, const int y_stride, + const rta_real_t * x, const int x_stride, const unsigned int x_size, + const rta_real_t f0, rta_real_t * state); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_ONEPOLE_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_preemphasis.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_preemphasis.c new file mode 100644 index 0000000000000000000000000000000000000000..25c7a6b7217489e40ea59fe9e2f86943ff5a93fc --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_preemphasis.c @@ -0,0 +1,104 @@ +/** + * @file rta_preemphasis.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Tue Sep 4 16:24:45 2007 + * + * @brief Preemphasis filtering + * + * Simple first order difference equation + * s(n) = s(n) - f * s(n-1) + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_preemphasis.h" + +/* can not be in place */ +/* previous_sample updated */ +void rta_preemphasis_signal(rta_real_t * out_samples, + const rta_real_t * in_samples, const unsigned int input_size, + rta_real_t * previous_sample, const rta_real_t factor) +{ + int i; + + if(factor != 0.) + { + out_samples[0] = in_samples[0] - factor * (*previous_sample); + + for(i=1; i<input_size; i++) + { + out_samples[i] = in_samples[i] - factor * in_samples[i-1]; + } + + } + else + { + for(i=0; i<input_size; i++) + { + out_samples[i] = in_samples[i]; + } + } + + *previous_sample = in_samples[input_size-1]; + + return; +} + +/* can not be in place */ +/* previous_sample updated */ +void rta_preemphasis_signal_stride(rta_real_t * out_samples, const int o_stride, + const rta_real_t * in_samples, const int i_stride, + const unsigned int input_size, + rta_real_t * previous_sample, const rta_real_t factor) +{ + int i,o; + + if(factor != 0.) + { + out_samples[0] = in_samples[0] - factor * (*previous_sample); + + for(i=i_stride, o=o_stride; i<input_size*i_stride; i+=i_stride, o+=o_stride) + { + out_samples[i] = in_samples[i] - factor * in_samples[i-1]; + } + } + else + { + for(i=0, o=0; i<input_size*i_stride; i+=i_stride, o+=o_stride) + { + out_samples[i] = in_samples[i]; + } + } + + *previous_sample = in_samples[i-i_stride]; + + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_preemphasis.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_preemphasis.h new file mode 100644 index 0000000000000000000000000000000000000000..788bf963eb88afecc355e21a037f08029f3aea90 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_preemphasis.h @@ -0,0 +1,99 @@ +/** + * @file rta_preemphasis.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Tue Sep 4 16:24:45 2007 + * + * @brief Preemphasis filtering + * + * Simple first order difference equation + * s(n) = s(n) - f * s(n-1) + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_PREEMPHASIS_H_ +#define _RTA_PREEMPHASIS_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Apply preemphasis of 'factor' on 'in_samples' as + * 'out_sample'[0] = 'in_samples'[0] - 'factor' * (*'previous_sample') + * 'out_sample'[i] = 'in_samples'[i] - 'factor' * 'in_samples'[i-1], i>0 + * + * This calculation can not be in place: 'out_sample' != 'in_sample' + * + * @param out_samples size is 'input_size' + * @param in_samples size is 'input_size' + * @param input_size is the number of input and output samples and must + * be > 0 + * @param previous_sample is updated as + * (*'previous_sample') = 'in_samples'['input_size'-1] + * @param factor is generally 0.97 for voice analysis + */ +void +rta_preemphasis_signal(rta_real_t * out_samples, + const rta_real_t * in_samples, const unsigned int input_size, + rta_real_t * previous_sample, const rta_real_t factor); + +/** + * Apply preemphasis of 'factor' on 'in_samples' as + * 'out_sample'[0] = 'in_samples'[0] - 'factor' * (*'previous_sample') + * 'out_sample'[i] = 'in_samples'[i] - 'factor' * 'in_samples'[i-1], i>0 + * + * This calculation can not be in place: 'out_sample' != 'in_sample' + * + * @param out_samples size is 'input_size' + * @param o_stride is 'out_samples' stride + * @param in_samples size is 'input_size' + * @param i_stride is 'input_size' stride + * @param input_size is the number of input and output samples and must + * be > 0 + * @param previous_sample is updated as + * (*'previous_sample') = 'in_samples'[('input_size'-1)*i_stride] + * @param factor is generally 0.97 for voice analysis + */ +void +rta_preemphasis_signal_stride(rta_real_t * out_samples, const int o_stride, + const rta_real_t * in_samples, const int i_stride, + const unsigned int input_size, + rta_real_t * previous_sample, const rta_real_t factor); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_PREEMPHASIS_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_resample.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_resample.c new file mode 100644 index 0000000000000000000000000000000000000000..ab51fa4d0c7e3641369813b60c2aa58072594676 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_resample.c @@ -0,0 +1,363 @@ +/** + * @file rta_resample.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Nov 12 18:21:06 2007 + * + * @brief Resample utilities + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_resample.h" +#include "rta_util.h" // for idefix + +/* contract: factor > 0; */ +/* o_size >= i_size / factor */ +void rta_downsample_int_mean(rta_real_t * output, + const rta_real_t * input, + const unsigned int i_size, + const unsigned int factor) +{ + const rta_real_t factor_inv = 1. / factor; + unsigned int i,j; + const unsigned int i_max = i_size / factor; + + switch(factor) + { + case 1: + for(i=0; i<i_max; i++) + { + output[i] = input[i]; + } + break; + + case 2: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1]); + } + break; + + case 3: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1] + input[j+2]); + } + break; + + case 4: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1] + input[j+2] + input[j+3]); + } + break; + + case 5: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1] + input[j+2] + input[j+3] + + input[j+4]); + } + break; + + case 6: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1] + input[j+2] + input[j+3] + + input[j+4] + input[j+5]); + } + break; + + case 7: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1] + input[j+2] + input[j+3] + + input[j+4] + input[j+5] + input[j+6]); + } + break; + + case 8: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = factor_inv * (input[j] + input[j+1] + input[j+2] + input[j+3] + + input[j+4] + input[j+5] + input[j+6] + input[j+7]); + } + break; + + default: + for(i=0, j=0; i<i_max; i++, j+=factor) + { + unsigned int k; + output[i] = input[j]; + for(k=1; k<factor; k++) + { + output[i] += input[j+k]; + } + output[i] *= factor_inv; + } + } + + return; +} + +/* contract: factor > 0; */ +/* o_size >= i_size / factor */ +void rta_downsample_int_mean_stride( + rta_real_t * output, const int o_stride, + const rta_real_t * input, const int i_stride, + const unsigned int i_size, + const unsigned int factor) +{ + const rta_real_t factor_inv = 1. / factor; + int o,i; + const int o_max = (i_size / factor) * o_stride; + const int i_incr = factor * i_stride; + + + switch(factor) + { + + case 1: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = input[i]; + } + break; + + case 2: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * (input[i] + input[i+i_stride]); + } + break; + + case 3: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * + (input[i] + input[i+i_stride] + input[i+2*i_stride]); + } + break; + + case 4: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * + (input[i] + input[i+i_stride] + input[i+2*i_stride] + + input[i+3*i_stride]); + } + break; + + case 5: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * + (input[i] + input[i+i_stride] + input[i+2*i_stride] + + input[i+3*i_stride] + input[i+4*i_stride]); + } + break; + + case 6: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * + (input[i] + input[i+i_stride] + input[i+2*i_stride] + + input[i+3*i_stride] + input[i+4*i_stride] + input[i+5*i_stride]); + } + break; + + case 7: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * + (input[i] + input[i+i_stride] + input[i+2*i_stride] + + input[i+3*i_stride] + input[i+4*i_stride] + input[i+5*i_stride] + + input[i+6*i_stride]); + } + break; + + case 8: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = factor_inv * + (input[i] + input[i+i_stride] + input[i+2*i_stride] + + input[i+3*i_stride] + input[i+4*i_stride] + input[i+5*i_stride] + + input[i+6*i_stride] + input[i+7*i_stride]); + } + break; + + default: + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + int ii; + output[o] = input[i]; + for(ii=i_stride; ii<i_incr; ii+=i_stride) + { + output[o] += input[i+ii]; + } + output[o] *= factor_inv; + } + } + + return; +} + +/* contract: factor > 0; */ +/* o_size >= i_size / factor */ +void rta_downsample_int_remove(rta_real_t * output, + const rta_real_t * input, + const unsigned int i_size, + const unsigned int factor) +{ + unsigned int i,j; + const unsigned int i_max = i_size / factor; + + for(i=0, j=0; i<i_max; i++, j+=factor) + { + output[i] = input[j]; + } + + return; +} + +/* contract: factor > 0; */ +/* o_size >= i_size / factor */ +void rta_downsample_int_remove_stride( + rta_real_t * output, const int o_stride, + const rta_real_t * input, const int i_stride, + const unsigned int i_size, + const unsigned int factor) +{ + int o,i; + const int o_max = (i_size / factor) * o_stride; + const int i_incr = factor * i_stride; + + for(o=0, i=0; o<o_max; o+=o_stride, i+=i_incr) + { + output[o] = input[i]; + } + + return; +} + + + +int rta_resample_cubic (rta_real_t * out_values, + const rta_real_t * in_values, + const unsigned int i_size, + const unsigned int i_channels, + const double factor) +{ + if (factor == 1.0) + { /* copy through */ + memcpy(out_values, in_values, i_size * i_channels * sizeof(rta_real_t)); + } + else if (in_values != out_values) + { + int m = i_size; + int n = i_channels; + + /* limit resampling range here? */ + if (m > 3) + { + double inv = 1.0 / factor; + int out_m = (int) floor((double) (m - 1) * inv) + 1; + int out_head_m = (int) ceil(inv); + int out_tailm2_m = (int) floor((double) (m - 2) * inv); + rta_idefix_t idefix; + rta_idefix_t incr; + int i, j; + + rta_idefix_set_float(&incr, factor); + + for (j = 0; j < n; j++) + { + rta_idefix_set_zero(&idefix); + + /* copy first points without interpolation */ + for (i = j; i < out_head_m * n; i += n) + { + int onset = rta_idefix_get_index(idefix); + float frac = rta_idefix_get_frac(idefix); + float left = in_values[j + onset * n]; + float right = in_values[j + onset * n + n]; + + //out_values[i] = rta_cubic_calc_stride_head(in_values[j + onset] * n, ft, n); + out_values[i] = left + (right - left) * frac; + rta_idefix_incr(&idefix, incr); + } + + for (; i < out_tailm2_m * n; i += n) + { + rta_cubic_idefix_interpolate_stride(in_values + j, idefix, n, out_values + i); + rta_idefix_incr(&idefix, incr); + } + + /* + for(; i<out_tailm1_m*n; i+=n) + { + rta_cubic_coefs_t *ft = rta_cubic_table + rta_cubic_get_table_index_from_idefix(idefix); + int onset = rta_idefix_get_index(idefix); + + out_values[i] = rta_cubic_calc_stride_tailm2(in_values + j + onset * n, ft, n); + rta_idefix_incr(&idefix, incr); + } + */ + + for (; i < out_m * n; i += n) + { + int onset = rta_idefix_get_index(idefix); + float frac = rta_idefix_get_frac(idefix); + float left = in_values[j + onset * n]; + float right = in_values[j + onset * n + n]; + + //out_values[i] = rta_cubic_calc_stride_head(in_values[j + onset] * n, ft, n); + out_values[i] = left + (right - left) * frac; + rta_idefix_incr(&idefix, incr); + } + } + } + else + return 0; + } + else + return 0; // can't run in-place + + return 1; +} + + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_resample.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_resample.h new file mode 100644 index 0000000000000000000000000000000000000000..8c6929ae376f771e40fb9db769473d2297219b65 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_resample.h @@ -0,0 +1,147 @@ +/** + * @file rta_resample.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 27 12:25:16 2007 + * + * @brief Resampling utilities + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_RESAMPLE_H_ +#define _RTA_RESAMPLE_H_ 1 + +#include "rta.h" +#include "rta_cubic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Downsample 'input' to 'output', by an integer factor, out of + * place. The 'output' samples are simple means of 'input' over + * 'factor' samples. The calculation can be in place if + * 'input' == 'output' . + * + * @param output size must be >= i_size / 'factor' + * @param input size is 'i_size' + * @param i_size is 'input' size + * @param factor must be > 0 + */ +void +rta_downsample_int_mean(rta_real_t * output, + const rta_real_t * input, const unsigned int i_size, + const unsigned int factor); + +/** + * Downsample 'input' to 'output', by an integer factor, out of + * place. The 'output' samples are simple means of 'input' over + * 'factor' samples. The calculation can be in place if + * 'input' == 'output' and 'i_stride' == 'o_stride'. + * + * @param output size must be >= i_size / 'factor' + * @param o_stride is 'output' stride + * @param input size is 'i_size' + * @param i_stride is 'input' stride + * @param i_size is 'input' size + * @param factor must be > 0 + */ +void +rta_downsample_int_mean_stride( + rta_real_t * output, const int o_stride, + const rta_real_t * input, const int i_stride, + const unsigned int i_size, + const unsigned int factor); + +/** + * Downsample 'input' to 'output', by an integer factor, out of + * place. The 'output' samples are 'input' values kept every + * 'factor' samples. The calculation can be in place if + * 'input' == 'output'. + * + * @param output size must be >= i_size / 'factor' + * @param input size is 'i_size' + * @param i_size is 'input' size + * @param factor must be > 0 + */ +void +rta_downsample_int_remove(rta_real_t * output, + const rta_real_t * input, + const unsigned int i_size, + const unsigned int factor); + +/** + * Downsample 'input' to 'output', by an integer factor, out of + * place. The 'output' samples are 'input' values kept every + * 'factor' samples. The calculation can be in place if + * 'input' == 'output' and 'i_stride' == 'o_stride'. + * + * @param output size must be >= i_size / 'factor' + * @param o_stride is 'output' stride + * @param input size is 'i_size' + * @param i_stride is 'input' stride + * @param i_size is 'input' size + * @param factor must be > 0 + */ +void +rta_downsample_int_remove_stride( + rta_real_t * output, const int o_stride, + const rta_real_t * input, const int i_stride, + const unsigned int i_size, + const unsigned int factor); + + + +/** + * Cubic resampling of interleaved 'input' to 'output' by a factor, out of + * place. + * + * @param output size must be >= i_size / 'factor' + * @param input size 'i_size' * 'i_channels' + * @param i_size is 'input' number of sample frames + * @param i_channels is 'input' number of interleaved channels + * @param factor must be > 0 + * @return 1 if successful, 0 otherwise (in-place or input too short) + */ +int +rta_resample_cubic (rta_real_t *output, + const rta_real_t *input, + const unsigned int i_size, + const unsigned int i_channels, + const double factor); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_RESAMPLE_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_selection.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_selection.c new file mode 100644 index 0000000000000000000000000000000000000000..04ea09f149806264755239d0a8295b240b87fe34 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_selection.c @@ -0,0 +1,294 @@ +/** + * @file rta_selection.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Wed Aug 27 22:12:15 2008 + * + * @brief RTA selection (median, quartile, etc.) + * + * Quick selection, qsort-like, with array selection (for median of a + * vector of even size among others). + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_selection.h" + +#include "rta_math.h" /* rta_floor, rta_ceil */ + +#ifdef WIN32 +#define inline +#endif + +static inline void rta_swap(rta_real_t * a, rta_real_t * b) +{ + register rta_real_t tmp = *b; + + *b = *a; + *a = tmp; + + return; +} + +/* quicksort-like */ +rta_real_t rta_selection(rta_real_t * input, const unsigned int i_size, const rta_real_t real_selection) +{ + /* low and high inner bounds */ + unsigned int l, h; + + /* partition indexes */ + unsigned int low = 0; + unsigned int mid; + unsigned int high = i_size - 1; + + rta_real_t selection_floor = rta_floor(real_selection); + unsigned int selection = (unsigned int) selection_floor; + + /* s_extension can be 1 in order to sort next index too, + to get real indexes selection */ + unsigned int s_extension = (unsigned int) rta_ceil(real_selection) - selection; + + while(high > low + 1) + { + mid = (low + high) >> 1; /* avoid overflow */ + + /* choose the pivot index as the median of */ + /* input[low], input[mid] and input[high] */ + + /* sort input[low], input[mid], input[high] in that order */ + if(input[mid] < input[low]) + { + rta_swap(input + mid, input + low); + } + /* input[low] <= input[mid] now */ + + if(input[high] < input[mid]) + { + rta_swap(input + high, input + mid); + /* input[mid] <= input[high] now */ + + /* input[low] and input[mid] may have changed */ + if(input[mid] < input[low]) + { + rta_swap(input + mid, input + low); + } + } + + /* put the pivot at the end, it is input[high] from now */ + rta_swap(input + mid, input + high); + + /* we already know that input[low] <= input[high] */ + /* but l will be incremented before any test */ + l = low; + /* the pivot is at index high */ + /* but h will be decremented before any test */ + h = high; + + for(;;) + { + while(input[++l] < input[high]) + { + /* void */ + } + + while(input[high] < input[--h]) + { + /* void */ + } + + if(h <= l) + { + break; + } + else + { + rta_swap(input + l, input + h); + } + } + + /* put the pivot back at index l */ + rta_swap(input + high, input + l); + + /* new partition containing selection */ + if(l <= selection) + { + low = l; + } + + /* (l >= selection + s_extension) for general case with */ + if(l >= selection + s_extension) + { + high = l; + } + } + + /* One or two elements left */ + if(high <= low + 1) + { + /* last sort */ + if(input[high] < input[low]) + { + rta_swap(input + high, input + low); + } + } + + { + rta_real_t ret; + if(s_extension == 0) + { + ret = input[selection]; + } + else + { + rta_real_t ratio = real_selection - selection_floor; + ret = ratio * input[selection] + (1. - ratio) * input[selection + 1]; + } + + return ret; + } +} + +rta_real_t rta_selection_stride(rta_real_t * input, const int i_stride, const unsigned int i_size, const rta_real_t real_selection) +{ + /* low and high inner bounds */ + int l, h; + + /* partition indexes */ + int low = 0; + int mid; + int high = (i_size - 1) * i_stride; + + rta_real_t selection_floor = rta_floor(real_selection); + int selection = ( (int) selection_floor ) * i_stride; + + /* s_extension can be 1 in order to sort next index too, + to get real indexes selection */ + int s_extension = ( (int) rta_ceil(real_selection) ) * i_stride - selection; + + while(high > low + i_stride) + { + mid = (((low + high)/i_stride) >> 1) * i_stride; /* avoid overflow */ + + /* choose the pivot index as the median of */ + /* input[low], input[mid] and input[high] */ + + /* sort input[low], input[mid], input[high] in that order */ + if(input[mid] < input[low]) + { + rta_swap(input + mid, input + low); + } + /* input[low] <= input[mid] now */ + + if(input[high] < input[mid]) + { + rta_swap(input + high, input + mid); + /* input[mid] <= input[high] now */ + + /* input[low] and input[mid] may have changed */ + if(input[mid] < input[low]) + { + rta_swap(input + mid, input + low); + } + } + + /* put the pivot at the end, it is input[high] from now */ + rta_swap(input + mid, input + high); + + /* we already know that input[low] <= input[high] */ + /* but l will be incremented before any test */ + l = low; + /* the pivot is at index high */ + /* but h will be decremented before any test */ + h = high; + + for(;;) + { + do + { + l += i_stride; + } + while(input[l] < input[high]); + + do + { + h -= i_stride; + } + while(input[high] < input[h]); + + if(h <= l) + { + break; + } + else + { + rta_swap(input + l, input + h); + } + } + + /* put the pivot back at index l */ + rta_swap(input + high, input + l); + + /* new partition containing selection */ + if(l <= selection) + { + low = l; + } + + if(l >= selection + s_extension) + { + high = l; + } + } + + /* One or two elements left */ + if(high <= low + i_stride) + { + /* last sort */ + if(input[high] < input[low]) + { + rta_swap(input + high, input + low); + } + } + + { + rta_real_t ret; + if(s_extension == 0) + { + ret = input[selection]; + } + else + { + rta_real_t ratio = real_selection - selection_floor; + ret = ratio * input[selection] + (1. - ratio) * input[selection + i_stride]; + } + + return ret; + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_selection.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_selection.h new file mode 100644 index 0000000000000000000000000000000000000000..e8b6b1d6ecabb02844314724175a5454bcf9a364 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_selection.h @@ -0,0 +1,116 @@ +/** + * @file rta_selection.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Wed Aug 27 22:12:15 2008 + * + * @brief RTA selection (median, quartile, etc.) + * + * Quick selection, qsort-like, with array selection (for median of a + * vector of even size among others). + * + * @copyright + * Copyright (C) 2007 - 2009 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_SELECTION_H_ +#define _RTA_SELECTION_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Quick selection of an index, as if the input was sorted. If the + * given index is not an integer, the weighted mean of the two + * adjacent indexes is returned. The median is then: + * median = rta_selection('input', 'i_size', 'i_size' * 0.5); + * + * This function operates in place and the input will be modified. + * + * The algorithm is similar to quick sort but not every element is + * sorted. After this function's call: + * 'input'[index] <= 'input'['selection'] for each (index < 'selection') + * 'input'[index] >= 'input'['selection'] for each (index > 'selection') + * + * @param input is a vector of size 'i_size' + * @param i_size is the size of 'input' + * @param selection must be bewteen 0 and i_size (note that a simple + * search is faster at finding the minimal or maximal element of a list). + * + * @return the value of: + * 'input'['selection'] if floor(selection) == selection, else + * the weighted mean of 'input'[floor('selection')] and + * 'input'[floor('selection')+1] (the weights are the relative difference + * between 'selection' and floor('selection'), and between + * 'selection' and floor('selection') + 1. + */ +rta_real_t rta_selection(rta_real_t * input, const unsigned int i_size, + const rta_real_t selection); + +/** + * Quick selection of an index, as if the input was sorted. If the + * given index is not an integer, the weighted mean of the two + * adjacent indexes is returned. The median is then: + * median = rta_selection('input', 'i_size', 'i_size' * 0.5); + * + * This function operates in place and the input will be modified. + * + * The algorithm is similar to quick sort but not every element is + * sorted. After this function's call: + * 'input'[index] <= 'input'['selection'] for each (index < 'selection') + * 'input'[index] >= 'input'['selection'] for each (index > 'selection') + * + * @param input is a vector of size 'i_size' + * @param i_stride is 'input' stride + * @param i_size is the size of 'input' + * @param selection must be bewteen 0 and i_size (note that a simple + * search is faster at finding the minimal or maximal element of a list). + * + * @return the value of: + * 'input'['selection'] if floor(selection) == selection, else + * the weighted mean of 'input'[floor('selection')] and + * 'input'[floor('selection')+1] (the weights are the relative difference + * between 'selection' and floor('selection'), and between + * 'selection' and floor('selection') + 1. + */ +rta_real_t rta_selection_stride(rta_real_t * input, + const int i_stride, + const unsigned int i_size, + const rta_real_t selection); + + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_SELECTION_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_svd.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_svd.c new file mode 100644 index 0000000000000000000000000000000000000000..6bec25d3b1484addfa0c3944a98c303e4cc97881 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_svd.c @@ -0,0 +1,1286 @@ +/** + * @file rta_svd.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 18 09:58:20 2008 + * + * @brief Singular Value Decomposition + * + * From the TNT/Jama package jama_svd.h (Adapted from JAMA, a Java + * Matrix Library, developed jointly by the Mathworks and NIST; see + * http://math.nist.gov/javanumerics/jama). + * + * @copyright + * Copyright (C) 2008 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_svd.h" +#include "rta_math.h" /* rta_abs, rta_max, rta_min, rta_hypot, rta_pow */ +#include "rta_int.h" /* rta_imin, rta_imax */ +#include "rta_float.h" /* RTA_REAL_EPSILON */ +#include "rta_stdlib.h" /* NULL */ + +struct rta_svd_setup +{ + rta_svd_t svd_type; + + /* A is copied when svd_type is 'rta_svd_out_of_place' + or n > m (transposition) */ + rta_real_t * A; /* matrix of size m x n */ + unsigned int m; + unsigned int n; + + /* internal workspaces */ + rta_real_t * e; /* vector of size min(m,n) */ + rta_real_t * work; /* vector of size max(m,n) */ +}; + +int +rta_svd_setup_new(rta_svd_setup_t ** svd_setup, const rta_svd_t svd_type, + rta_real_t * U, rta_real_t * S, rta_real_t * V, + rta_real_t * A, const unsigned int m, const unsigned int n) +{ + int ret = 1; + *svd_setup = (rta_svd_setup_t *) rta_malloc(sizeof(rta_svd_setup_t)); + + if(*svd_setup == NULL) + { + ret = 0; + } + else + { + (*svd_setup)->svd_type = svd_type; + (*svd_setup)->m = m; + (*svd_setup)->n = n; + } + + if(ret != 0) + { + if(svd_type == rta_svd_out_of_place || n > m) + { + (*svd_setup)->A = (float *)rta_malloc(m * n * sizeof(rta_real_t)); + if((*svd_setup)->A == NULL) + { + ret = 0; + } + } + else + { + (*svd_setup)->A = NULL; + } + } + + if(ret != 0) + { + (*svd_setup)->e = (rta_real_t *) rta_malloc( + rta_imin(m,n) * sizeof(rta_real_t)); + if((*svd_setup)->e == NULL) + { + ret = 0; + } + } + + if(ret != 0) + { + (*svd_setup)-> work = (rta_real_t *) rta_malloc( + rta_imax(m,n) * sizeof(rta_real_t)); + if((*svd_setup)->work == NULL) + { + ret = 0; + } + } + + if(ret == 0) + { + rta_svd_setup_delete(*svd_setup); + } + + return ret; +} + +void +rta_svd_setup_delete(rta_svd_setup_t * svd_setup) +{ + if(svd_setup != NULL) + { + if((svd_setup)->A != NULL) + { + rta_free((svd_setup)->A); + } + + if((svd_setup)->e != NULL) + { + rta_free((svd_setup)->e); + } + + if((svd_setup)->work != NULL) + { + rta_free((svd_setup)->work); + } + + rta_free(svd_setup); + } + + return; +} + +/* A = U * S * V' */ + +/* A is a 2D array of size m x n */ +/* U is a 2D array of size m x (m,n) */ +/* S is a 1D array of size min(m,n) */ +/* V is a 2D array of size n x min(n,m) */ + +/* 2D arrays are in row-major order */ +/* A can be modified by the computation (or copied first, depends on setup) */ +/* U and V can be NULL and are not computed, then */ + +/* e is a 1D array of size n */ +/* work is a 1D array of size m */ +void +rta_svd(rta_real_t * output_U, rta_real_t * S, rta_real_t * output_V, + rta_real_t * input_A, const rta_svd_setup_t * svd_setup) +{ + rta_real_t * A; /* input_A, copied or transposed into svd_setup->A */ + rta_real_t * U; /* swap with V if A is transposed */ + rta_real_t * V; + + rta_real_t * e = svd_setup->e; /* just to ease the reading */ + rta_real_t * work = svd_setup->work; /* just to ease the reading */ + + unsigned int m = svd_setup->m; + unsigned int n = svd_setup->n; + + int nu; + int nct; + int nrt; + + int i, j, k; + int p, pp, iter; + + if(n <= m) + { + if(svd_setup->svd_type == rta_svd_out_of_place) + { + /* Use an input copy */ + A = svd_setup->A; + j = m*n; + for(i = 0; i<j; i++) + { + A[i] = input_A[i]; + } + } + else /* Work directly on input */ + { + A = input_A; + } + + U = output_U; + V = output_V; + } + else + { + /* Use an input transposed copy */ + A = svd_setup->A; + + for(i = 0; i<m; i++) + { + for(j=0; j<n; j++) + { + A[j*m + i] = input_A[i*n + j]; + } + } + m = svd_setup->n; + n = svd_setup->m; + + /* swap U and V as A is transposed */ + U = output_V; + V = output_U; + } + + nu = rta_imin(m,n); + nct = rta_imin(m-1,n); + nrt = rta_imax(0,rta_imin(n-2,m)); + + /* Reduce A to bidiagonal form, storing the diagonal elements */ + /* in s and the super-diagonal elements in e. */ + for (k = 0; k < rta_imax(nct,nrt); k++) + { + if (k < nct) + { + /* Compute the transformation for the k-th column and */ + /* place the k-th diagonal in S[k]. */ + /* Compute 2-norm of k-th column without under/overflow. */ + S[k] = 0.0; + for (i = k; i < m; i++) + { + S[k] = rta_hypot(S[k],A[i*n + k]); + } + if (S[k] != 0.0) + { + if (A[k*n + k] < 0.0) + { + S[k] = -S[k]; + } + for (i = k; i < m; i++) + { + A[i*n + k] /= S[k]; + } + A[k*n + k] += 1.0; + } + S[k] = -S[k]; + } + for (j = k+1; j < n; j++) + { + if ((k < nct) && (S[k] != 0.0)) + { + /* Apply the transformation. */ + rta_real_t t = 0.0; + for (i = k; i < m; i++) + { + t += A[i*n + k]*A[i*n + j]; + } + t = -t/A[k*n + k]; + for (i = k; i < m; i++) + { + A[i*n + j] += t*A[i*n + k]; + } + } + + /* Place the k-th row of A into e for the */ + /* subsequent calculation of the row transformation. */ + e[j] = A[k*n + j]; + } + if (U != NULL && (k < nct)) + { + /* U initialisation */ + for(i=0; i<k; i++) + { + U[i*n + k] = 0.0; + } + + /* Place the transformation in U for subsequent back */ + /* multiplication. */ + for (i = k; i < m; i++) + { + U[i*n + k] = A[i*n + k]; + } + } + if (k < nrt) + { + /* Compute the k-th row transformation and place the */ + /* k-th super-diagonal in e[k]. */ + /* Compute 2-norm without under/overflow. */ + e[k] = 0.0; + for (i = k+1; i < n; i++) + { + e[k] = rta_hypot(e[k],e[i]); + } + if (e[k] != 0.0) + { + if (e[k+1] < 0.0) + { + e[k] = -e[k]; + } + for (i = k+1; i < n; i++) + { + e[i] /= e[k]; + } + e[k+1] += 1.0; + } + e[k] = -e[k]; + if ((k+1 < m) && (e[k] != 0.0)) + { + /* Apply the transformation. */ + for (i = k+1; i < m; i++) + { + work[i] = 0.0; + } + for (j = k+1; j < n; j++) + { + for (i = k+1; i < m; i++) + { + work[i] += e[j]*A[i*n + j]; + } + } + for (j = k+1; j < n; j++) + { + rta_real_t t = -e[j]/e[k+1]; + for (i = k+1; i < m; i++) + { + A[i*n + j] += t*work[i]; + } + } + } + if (V != NULL) + { + /* V initialisation */ + for(i=0; i<k+1; i++) + { + V[i*n + k] = 0.0; + } + + /* Place the transformation in V for subsequent */ + /* back multiplication. */ + for (i = k+1; i < n; i++) + { + V[i*n + k] = e[i]; + } + } + } + } + + /* Set up the final bidiagonal matrix or order p. */ + p = rta_imin(n,m+1); + if (nct < n) + { + S[nct] = A[nct*n + nct]; + } + if (m < p) + { + S[p-1] = 0.0; + } + if (nrt+1 < p) + { + e[nrt] = A[nrt*n + (p-1)]; + } + e[p-1] = 0.0; + + /* If required, generate U. */ + if (U != NULL) + { + for (j = nct; j < nu; j++) + { + for (i = 0; i < m; i++) + { + U[i*n + j] = 0.0; + } + U[j*n + j] = 1.0; + } + for (k = nct-1; k >= 0; k--) + { + if (S[k] != 0.0) + { + for (j = k+1; j < nu; j++) + { + rta_real_t t = 0.0; + for (i = k; i < m; i++) + { + t += U[i*n + k]*U[i*n + j]; + } + t = -t/U[k*n + k]; + for (i = k; i < m; i++) + { + U[i*n + j] += t*U[i*n + k]; + } + } + for (i = k; i < m; i++ ) + { + U[i*n + k] = -U[i*n + k]; + } + U[k*n + k] = 1.0 + U[k*n + k]; + for (i = 0; i < k-1; i++) + { + U[i*n + k] = 0.0; + } + } + else + { + for (i = 0; i < m; i++) + { + U[i*n + k] = 0.0; + } + U[k*n + k] = 1.0; + } + } + } + + /* If required, generate V. */ + if (V != NULL) + { + for (k = n-1; k >= 0; k--) + { + if ((k < nrt) && (e[k] != 0.0)) + { + for (j = k+1; j < nu; j++) + { + rta_real_t t = 0.0; + for (i = k+1; i < n; i++) + { + t += V[i*n + k]*V[i*n + j]; + } + t = -t/V[(k+1)*n + k]; + for (i = k+1; i < n; i++) + { + V[i*n + j] += t*V[i*n + k]; + } + } + } + for (i = 0; i < n; i++) + { + V[i*n + k] = 0.0; + } + V[k*n + k] = 1.0; + } + } + + /* Main iteration loop for the singular values. */ + pp = p-1; + iter = 0; + + while (p > 0) + { + int k=0; + int kase=0; + + /* Here is where a test for too many iterations would go. */ + + /* This section of the program inspects for */ + /* negligible elements in the s and e arrays. On */ + /* completion the variables kase and k are set as follows. */ + + /* kase = 1 if s(p) and e[k-1] are negligible and k<p */ + /* kase = 2 if s(k) is negligible and k<p */ + /* kase = 3 if e[k-1] is negligible, k<p, and */ + /* s(k), ..., s(p) are not negligible (qr step). */ + /* kase = 4 if e(p-1) is negligible (convergence). */ + + for (k = p-2; k >= -1; k--) + { + if (k == -1) + { + break; + } + if (rta_abs(e[k]) <= RTA_REAL_MIN || + rta_abs(e[k]) <= RTA_REAL_EPSILON * (rta_abs(S[k]) + rta_abs(S[k+1]))) + { + e[k] = 0.0; + break; + } + } + if (k == p-2) + { + kase = 4; + } + else + { + int ks; + rta_real_t t; + for (ks = p-1; ks >= k; ks--) + { + if (ks == k) + { + break; + } + t = (ks != p ? rta_abs(e[ks]) : 0.) + (ks != k+1 ? rta_abs(e[ks-1]) : 0.); + if (rta_abs(S[ks]) <= RTA_REAL_MIN || + rta_abs(S[ks]) <= RTA_REAL_EPSILON * t) + { + S[ks] = 0.0; + break; + } + } + if (ks == k) + { + kase = 3; + } + else if (ks == p-1) + { + kase = 1; + } + else + { + kase = 2; + k = ks; + } + } + k++; + + /* Perform the task indicated by kase. */ + switch (kase) + { + /* Deflate negligible s(p). */ + case 1: + { + rta_real_t f = e[p-2]; + e[p-2] = 0.0; + for (j = p-2; j >= k; j--) + { + rta_real_t t = rta_hypot(S[j],f); + rta_real_t cs = S[j]/t; + rta_real_t sn = f/t; + S[j] = t; + if (j != k) + { + f = -sn*e[j-1]; + e[j-1] = cs*e[j-1]; + } + if (V != NULL) + { + for (i = 0; i < n; i++) + { + t = cs*V[i*n + j] + sn*V[i*n + (p-1)]; + V[i*n + (p-1)] = -sn*V[i*n + j] + cs*V[i*n + (p-1)]; + V[i*n + j] = t; + } + } + } + } + break; + + /* Split at negligible s(k). */ + case 2: + { + rta_real_t f = e[k-1]; + e[k-1] = 0.0; + for (j = k; j < p; j++) + { + rta_real_t t = rta_hypot(S[j],f); + rta_real_t cs = S[j]/t; + rta_real_t sn = f/t; + S[j] = t; + f = -sn*e[j]; + e[j] = cs*e[j]; + if (U != NULL) + { + for (i = 0; i < m; i++) + { + t = cs*U[i*n + j] + sn*U[i*n + (k-1)]; + U[i*n + (k-1)] = -sn*U[i*n + j] + cs*U[i*n + (k-1)]; + U[i*n + j] = t; + } + } + } + } + break; + + /* Perform one qr step. */ + case 3: + { + /* Calculate the shift. */ + rta_real_t scale = + rta_max(rta_max(rta_max(rta_max(rta_abs(S[p-1]), rta_abs(S[p-2])), + rta_abs(e[p-2])), rta_abs(S[k])),rta_abs(e[k])); + rta_real_t sp = S[p-1]/scale; + rta_real_t spm1 = S[p-2]/scale; + rta_real_t epm1 = e[p-2]/scale; + rta_real_t sk = S[k]/scale; + rta_real_t ek = e[k]/scale; + rta_real_t b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; + rta_real_t c = (sp*epm1)*(sp*epm1); + rta_real_t shift = 0.0; + rta_real_t f; + rta_real_t g; + + if ((b != 0.0) || (c != 0.0)) + { + shift = sqrt(b*b + c); + if (b < 0.0) + { + shift = -shift; + } + shift = c/(b + shift); + } + f = (sk + sp)*(sk - sp) + shift; + g = sk*ek; + + /* Chase zeros. */ + for (j = k; j < p-1; j++) + { + rta_real_t t = rta_hypot(f,g); + rta_real_t cs = f/t; + rta_real_t sn = g/t; + if (j != k) + { + e[j-1] = t; + } + f = cs*S[j] + sn*e[j]; + e[j] = cs*e[j] - sn*S[j]; + g = sn*S[j+1]; + S[j+1] = cs*S[j+1]; + if (V != NULL) + { + for (i = 0; i < n; i++) + { + t = cs*V[i*n + j] + sn*V[i*n + (j+1)]; + V[i*n + (j+1)] = -sn*V[i*n + j] + cs*V[i*n + (j+1)]; + V[i*n + j] = t; + } + } + t = rta_hypot(f,g); + cs = f/t; + sn = g/t; + S[j] = t; + f = cs*e[j] + sn*S[j+1]; + S[j+1] = -sn*e[j] + cs*S[j+1]; + g = sn*e[j+1]; + e[j+1] = cs*e[j+1]; + if (U != NULL && (j < m-1)) + { + for (i = 0; i < m; i++) + { + t = cs*U[i*n + j] + sn*U[i*n + (j+1)]; + U[i*n + (j+1)] = -sn*U[i*n + j] + cs*U[i*n + (j+1)]; + U[i*n + j] = t; + } + } + } + e[p-2] = f; + iter = iter + 1; + } + break; + + /* Convergence. */ + case 4: + { + /* Make the singular values positive. */ + if (S[k] <= 0.0) + { + S[k] = (S[k] < 0.0 ? -S[k] : 0.0); + if (V != NULL) + { + for (i = 0; i <= pp; i++) + { + V[i*n + k] = -V[i*n + k]; + } + } + } + + /* Order the singular values. */ + while (k < pp) + { + rta_real_t t; + if (S[k] >= S[k+1]) + { + break; + } + t = S[k]; + S[k] = S[k+1]; + S[k+1] = t; + if (V != NULL && (k < n-1)) + { + for (i = 0; i < n; i++) + { + t = V[i*n + (k+1)]; + V[i*n + (k+1)] = V[i*n + k]; + V[i*n + k] = t; + } + } + if (U != NULL && (k < m-1)) + { + for (i = 0; i < m; i++) + { + t = U[i*n + (k+1)]; + U[i*n + (k+1)] = U[i*n + k]; + U[i*n + k] = t; + } + } + k++; + } + iter = 0; + p--; + } + break; + } + } + return; +} + +void +rta_svd_stride(rta_real_t * output_U, const int ou_stride, + rta_real_t * S, const int s_stride, + rta_real_t * output_V, const int ov_stride, + rta_real_t * input_A, const int ia_stride, + const rta_svd_setup_t * svd_setup) +{ + rta_real_t * A; /* input_A, copied or transposed into svd_setup->A */ + int a_stride; /* actual A stride */ + rta_real_t * U; /* swap with V if A is transposed */ + int u_stride; /* actual U stride */ + rta_real_t * V; + int v_stride; /* actual V stride */ + + + rta_real_t * e = svd_setup->e; /* just to ease the reading */ + rta_real_t * work = svd_setup->work; /* just to ease the reading */ + + unsigned int m = svd_setup->m; + unsigned int n = svd_setup->n; + + int nu; + int nct; + int nrt; + + int i, j, k; + int p, pp, iter; + + if(n <= m) + { + if(svd_setup->svd_type == rta_svd_out_of_place) + { + /* Use an input copy */ + A = svd_setup->A; + a_stride = 1; + j = m*n; + for(i = 0; i<j; i++) + { + A[i] = input_A[i*ia_stride]; + } + } + else /* Work directly on input */ + { + A = input_A; + a_stride = ia_stride; + } + + U = output_U; + u_stride = ou_stride; + V = output_V; + v_stride = ov_stride; + } + else + { + /* Use an input transposed copy */ + A = svd_setup->A; + a_stride = 1; + + for(i = 0; i<m; i++) + { + for(j=0; j<n; j++) + { + A[j*m + i] = input_A[(i*n + j)*ia_stride]; + } + } + m = svd_setup->n; + n = svd_setup->m; + + /* swap U and V as A is transposed */ + U = output_V; + u_stride = ov_stride; + V = output_U; + v_stride = ou_stride; + } + + nu = rta_imin(m,n); + nct = rta_imin(m-1,n); + nrt = rta_imax(0,rta_imin(n-2,m)); + + /* Reduce A to bidiagonal form, storing the diagonal elements */ + /* in s and the super-diagonal elements in e. */ + for (k = 0; k < rta_imax(nct,nrt); k++) + { + if (k < nct) + { + /* Compute the transformation for the k-th column and */ + /* place the k-th diagonal in S[k]. */ + /* Compute 2-norm of k-th column without under/overflow. */ + S[k*s_stride] = 0.0; + for (i = k; i < m; i++) + { + S[k*s_stride] = rta_hypot(S[k*s_stride],A[(i*n + k)*a_stride]); + } + if (S[k*s_stride] != 0.0) + { + if (A[(k*n + k)*a_stride] < 0.0) + { + S[k*s_stride] = -S[k*s_stride]; + } + for (i = k; i < m; i++) + { + A[(i*n + k)*a_stride] /= S[k*s_stride]; + } + A[(k*n + k)*a_stride] += 1.0; + } + S[k*s_stride] = -S[k*s_stride]; + } + for (j = k+1; j < n; j++) + { + if ((k < nct) && (S[k*s_stride] != 0.0)) + { + /* Apply the transformation. */ + rta_real_t t = 0.0; + for (i = k; i < m; i++) + { + t += A[(i*n + k)*a_stride]*A[(i*n + j)*a_stride]; + } + t = -t/A[(k*n + k)*a_stride]; + for (i = k; i < m; i++) + { + A[(i*n + j)*a_stride] += t*A[(i*n + k)*a_stride]; + } + } + + /* Place the k-th row of A into e for the */ + /* subsequent calculation of the row transformation. */ + e[j] = A[(k*n + j)*a_stride]; + } + if (U != NULL && (k < nct)) + { + /* U initialisation */ + for(i=0; i<k; i++) + { + U[(i*n + k)*u_stride] = 0.0; + } + + /* Place the transformation in U for subsequent back */ + /* multiplication. */ + for (i = k; i < m; i++) + { + U[(i*n + k)*u_stride] = A[(i*n + k)*a_stride]; + } + } + if (k < nrt) + { + /* Compute the k-th row transformation and place the */ + /* k-th super-diagonal in e[k]. */ + /* Compute 2-norm without under/overflow. */ + e[k] = 0.0; + for (i = k+1; i < n; i++) + { + e[k] = rta_hypot(e[k],e[i]); + } + if (e[k] != 0.0) + { + if (e[k+1] < 0.0) + { + e[k] = -e[k]; + } + for (i = k+1; i < n; i++) + { + e[i] /= e[k]; + } + e[k+1] += 1.0; + } + e[k] = -e[k]; + if ((k+1 < m) && (e[k] != 0.0)) + { + /* Apply the transformation. */ + for (i = k+1; i < m; i++) + { + work[i] = 0.0; + } + for (j = k+1; j < n; j++) + { + for (i = k+1; i < m; i++) + { + work[i] += e[j]*A[i*n + j]; + } + } + for (j = k+1; j < n; j++) + { + rta_real_t t = -e[j]/e[k+1]; + for (i = k+1; i < m; i++) + { + A[(i*n + j)*a_stride] += t*work[i]; + } + } + } + if (V != NULL) + { + /* V initialisation */ + for(i=0; i<k+1; i++) + { + V[(i*n + k)*v_stride] = 0.0; + } + + /* Place the transformation in V for subsequent */ + /* back multiplication. */ + for (i = k+1; i < n; i++) + { + V[(i*n + k)*v_stride] = e[i]; + } + } + } + } + + /* Set up the final bidiagonal matrix or order p. */ + p = rta_imin(n,m+1); + if (nct < n) + { + S[nct*s_stride] = A[(nct*n + nct)*a_stride]; + } + if (m < p) + { + S[(p-1)*s_stride] = 0.0; + } + if (nrt+1 < p) + { + e[nrt] = A[(nrt*n + (p-1))*a_stride]; + } + e[p-1] = 0.0; + + /* If required, generate U. */ + if (U != NULL) + { + for (j = nct; j < nu; j++) + { + for (i = 0; i < m; i++) + { + U[(i*n + j)*u_stride] = 0.0; + } + U[(j*n + j)*u_stride] = 1.0; + } + for (k = nct-1; k >= 0; k--) + { + if (S[k*s_stride] != 0.0) + { + for (j = k+1; j < nu; j++) + { + rta_real_t t = 0.0; + for (i = k; i < m; i++) + { + t += U[(i*n + k)*u_stride]*U[(i*n + j)*u_stride]; + } + t = -t/U[(k*n + k)*u_stride]; + for (i = k; i < m; i++) + { + U[(i*n + j)*u_stride] += t*U[(i*n + k)*u_stride]; + } + } + for (i = k; i < m; i++ ) + { + U[(i*n + k)*u_stride] = -U[(i*n + k)*u_stride]; + } + U[(k*n + k)*u_stride] = 1.0 + U[(k*n + k)*u_stride]; + for (i = 0; i < k-1; i++) + { + U[(i*n + k)*u_stride] = 0.0; + } + } + else + { + for (i = 0; i < m; i++) + { + U[(i*n + k)*u_stride] = 0.0; + } + U[(k*n + k)*u_stride] = 1.0; + } + } + } + + /* If required, generate V. */ + if (V != NULL) + { + for (k = n-1; k >= 0; k--) + { + if ((k < nrt) && (e[k] != 0.0)) + { + for (j = k+1; j < nu; j++) + { + rta_real_t t = 0.0; + for (i = k+1; i < n; i++) + { + t += V[(i*n + k)*v_stride]*V[(i*n + j)*v_stride]; + } + t = -t/V[((k+1)*n + k)*v_stride]; + for (i = k+1; i < n; i++) + { + V[(i*n + j)*v_stride] += t*V[(i*n + k)*v_stride]; + } + } + } + for (i = 0; i < n; i++) + { + V[(i*n + k)*v_stride] = 0.0; + } + V[(k*n + k)*v_stride] = 1.0; + } + } + + /* Main iteration loop for the singular values. */ + pp = p-1; + iter = 0; + + while (p > 0) + { + int k=0; + int kase=0; + + /* Here is where a test for too many iterations would go. */ + + /* This section of the program inspects for */ + /* negligible elements in the s and e arrays. On */ + /* completion the variables kase and k are set as follows. */ + + /* kase = 1 if s(p) and e[k-1] are negligible and k<p */ + /* kase = 2 if s(k) is negligible and k<p */ + /* kase = 3 if e[k-1] is negligible, k<p, and */ + /* s(k), ..., s(p) are not negligible (qr step). */ + /* kase = 4 if e(p-1) is negligible (convergence). */ + + for (k = p-2; k >= -1; k--) + { + if (k == -1) + { + break; + } + if (rta_abs(e[k]) <= RTA_REAL_MIN || + rta_abs(e[k]) <= RTA_REAL_EPSILON * + (rta_abs(S[k*s_stride]) + rta_abs(S[(k+1)*s_stride]))) + { + e[k] = 0.0; + break; + } + } + if (k == p-2) + { + kase = 4; + } + else + { + int ks; + rta_real_t t; + for (ks = p-1; ks >= k; ks--) + { + if (ks == k) + { + break; + } + t = (ks != p ? rta_abs(e[ks]) : 0.) + (ks != k+1 ? rta_abs(e[ks-1]) : 0.); + if (rta_abs(S[ks*s_stride]) <= RTA_REAL_MIN || + rta_abs(S[ks*s_stride]) <= RTA_REAL_EPSILON * t) + { + S[ks*s_stride] = 0.0; + break; + } + } + if (ks == k) + { + kase = 3; + } + else if (ks == p-1) + { + kase = 1; + } + else + { + kase = 2; + k = ks; + } + } + k++; + + /* Perform the task indicated by kase. */ + switch (kase) + { + /* Deflate negligible s(p). */ + case 1: + { + rta_real_t f = e[p-2]; + e[p-2] = 0.0; + for (j = p-2; j >= k; j--) + { + rta_real_t t = rta_hypot(S[j*s_stride],f); + rta_real_t cs = S[j*s_stride]/t; + rta_real_t sn = f/t; + S[j*s_stride] = t; + if (j != k) + { + f = -sn*e[j-1]; + e[j-1] = cs*e[j-1]; + } + if (V != NULL) + { + for (i = 0; i < n; i++) + { + t = cs*V[(i*n + j)*v_stride] + sn*V[(i*n + (p-1))*v_stride]; + V[(i*n + (p-1))*v_stride] = + -sn*V[(i*n + j)*v_stride] + cs*V[(i*n + (p-1))*v_stride]; + V[(i*n + j)*v_stride] = t; + } + } + } + } + break; + + /* Split at negligible s(k). */ + case 2: + { + rta_real_t f = e[k-1]; + e[k-1] = 0.0; + for (j = k; j < p; j++) + { + rta_real_t t = rta_hypot(S[j*s_stride],f); + rta_real_t cs = S[j*s_stride]/t; + rta_real_t sn = f/t; + S[j*s_stride] = t; + f = -sn*e[j]; + e[j] = cs*e[j]; + if (U != NULL) + { + for (i = 0; i < m; i++) + { + t = cs*U[(i*n + j)*u_stride] + sn*U[(i*n + (k-1))*u_stride]; + U[(i*n + (k-1))*u_stride] = + -sn*U[(i*n + j)*u_stride] + cs*U[(i*n + (k-1))*u_stride]; + U[(i*n + j)*u_stride] = t; + } + } + } + } + break; + + /* Perform one qr step. */ + case 3: + { + /* Calculate the shift. */ + rta_real_t scale = + rta_max(rta_max(rta_max(rta_max(rta_abs( + S[(p-1)*s_stride]), + rta_abs(S[(p-2)*s_stride])), + rta_abs(e[p-2])), + rta_abs(S[k*s_stride])), + rta_abs(e[k])); + + rta_real_t sp = S[(p-1)*s_stride]/scale; + rta_real_t spm1 = S[(p-2)*s_stride]/scale; + rta_real_t epm1 = e[p-2]/scale; + rta_real_t sk = S[k*s_stride]/scale; + rta_real_t ek = e[k]/scale; + rta_real_t b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; + rta_real_t c = (sp*epm1)*(sp*epm1); + rta_real_t shift = 0.0; + rta_real_t f; + rta_real_t g; + + if ((b != 0.0) || (c != 0.0)) + { + shift = sqrt(b*b + c); + if (b < 0.0) + { + shift = -shift; + } + shift = c/(b + shift); + } + f = (sk + sp)*(sk - sp) + shift; + g = sk*ek; + + /* Chase zeros. */ + for (j = k; j < p-1; j++) + { + rta_real_t t = rta_hypot(f,g); + rta_real_t cs = f/t; + rta_real_t sn = g/t; + if (j != k) + { + e[j-1] = t; + } + f = cs*S[j*s_stride] + sn*e[j]; + e[j] = cs*e[j] - sn*S[j*s_stride]; + g = sn*S[(j+1)*s_stride]; + S[(j+1)*s_stride] = cs*S[(j+1)*s_stride]; + if (V != NULL) + { + for (i = 0; i < n; i++) + { + t = cs*V[(i*n + j)*v_stride] + sn*V[(i*n + (j+1))*v_stride]; + V[(i*n + (j+1))*v_stride] = + -sn*V[(i*n + j)*v_stride] + cs*V[(i*n + (j+1))*v_stride]; + V[(i*n + j)*v_stride] = t; + } + } + t = rta_hypot(f,g); + cs = f/t; + sn = g/t; + S[j*s_stride] = t; + f = cs*e[j] + sn*S[(j+1)*s_stride]; + S[(j+1)*s_stride] = -sn*e[j] + cs*S[(j+1)*s_stride]; + g = sn*e[j+1]; + e[j+1] = cs*e[j+1]; + if (U != NULL && (j < m-1)) + { + for (i = 0; i < m; i++) + { + t = cs*U[(i*n + j)*u_stride] + sn*U[(i*n + (j+1))*u_stride]; + U[(i*n + (j+1))*u_stride] = + -sn*U[(i*n + j)*u_stride] + cs*U[(i*n + (j+1))*u_stride]; + U[(i*n + j)*u_stride] = t; + } + } + } + e[p-2] = f; + iter = iter + 1; + } + break; + + /* Convergence. */ + case 4: + { + /* Make the singular values positive. */ + if (S[k*s_stride] <= 0.0) + { + S[k*s_stride] = (S[k*s_stride] < 0.0 ? -S[k*s_stride] : 0.0); + if (V != NULL) + { + for (i = 0; i <= pp; i++) + { + V[(i*n + k)*v_stride] = -V[(i*n + k)*v_stride]; + } + } + } + + /* Order the singular values. */ + while (k < pp) + { + rta_real_t t; + if (S[k*s_stride] >= S[(k+1)*s_stride]) + { + break; + } + t = S[k*s_stride]; + S[k*s_stride] = S[(k+1)*s_stride]; + S[(k+1)*s_stride] = t; + if (V != NULL && (k < n-1)) + { + for (i = 0; i < n; i++) + { + t = V[(i*n + (k+1))*v_stride]; + V[(i*n + (k+1))*v_stride] = V[(i*n + k)*v_stride]; + V[(i*n + k)*v_stride] = t; + } + } + if (U != NULL && (k < m-1)) + { + for (i = 0; i < m; i++) + { + t = U[(i*n + (k+1))*u_stride]; + U[(i*n + (k+1)*u_stride)] = U[(i*n + k)*u_stride]; + U[(i*n + k)*u_stride] = t; + } + } + k++; + } + iter = 0; + p--; + } + break; + } + } + return; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_svd.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_svd.h new file mode 100644 index 0000000000000000000000000000000000000000..01d7b382ad3b43eba9131b886f14f940bffcbd10 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_svd.h @@ -0,0 +1,186 @@ +/** + * @file rta_svd.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Mon Aug 18 09:58:20 2008 + * + * @brief Singular Value Decomposition + * + * @copyright + * Copyright (C) 2008 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_SVD_H_ +#define _RTA_SVD_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + rta_svd_out_of_place = 1, /**< the input matrix A is first copied */ + rta_svd_in_place = 2 /**< the input matrix A can be modified */ +} rta_svd_t; + + +/* rta_svd_setup is private (depends on implementation) */ +typedef struct rta_svd_setup rta_svd_setup_t; + + +/** + * Allocate an svd setup for further svd decomposition. (The values + * referenced by the arrays may change, but not their sizes.) + * + * Any 2D array is in row-major order. + * + * \see rta_svd_setup_delete + * \see rta_svd + * + * @param svd_setup is an address to a pointer to a private structure + * which may depend on actual svd implementation. + * @param svd_type can be + * 'rta_svd_out_of_place': the matrix 'A' is first copied; + * 'rta_svd_in_place': 'A' may be modified. This is the most + * efficient if 'm' >= 'n'. (If 'n' > ''m, 'A' is internally + * copied and transposed.) + * @param U is a 2D array of size 'm' x 'n', or a 'NULL' pointer (it + * is not calculated, then). + * @param S is a 1D array of size 'n', representing the diagonal matrix + * of the singular values of 'A'. + * @param V is a 2D array f size 'n' x 'n', or a 'NULL' pointer (it is + * not calculated, then). + * @param A is a 2D array of size 'm' x 'n'. 'A' can be modified by the + * computation if 'svd_type' is 'rta_svd_in_place'. + * @param m is the first dimension of 'A'. + * @param n is the second dimension of 'A'. + * + * @return 1 on success, 0 on fail. If it fails, nothing should be done + * with 'svd_setup' (even a delete). + */ +int +rta_svd_setup_new(rta_svd_setup_t ** svd_setup, const rta_svd_t svd_type, + rta_real_t * U, rta_real_t * S, rta_real_t * V, + rta_real_t * A, const unsigned int m, const unsigned int n); + +/** + * Deallocate any (sucessfully) allocated svd setup. + * + * \see rta_svd_setup_new + * + * @param svd_setup is a pointer to the memory wich will be released. + */ +void +rta_svd_setup_delete(rta_svd_setup_t * svd_setup); + +/** + * + * For an m-by-n matrix A with m >= n, the singular value + * decomposition is an m-by-n orthogonal matrix U, an n-by-n diagonal + * matrix S, and an n-by-n orthogonal matrix V so that A = U*S*V'. + * (V' is the conjugate transpose of V and only the diagonal vector of + * S is represented here.) + * + * The singular values, S[k] are ordered so that + * S[0] >= S[1] >= ... >= S[n-1]. + * + * The singular value decompostion always exists, so the constructor will + * never fail. The matrix condition number and the effective numerical + * rank can be computed from the singlar values. + * + * Any array must be allocated before calling this function. + * Any 2D array is in row-major order. + * + * \see rta_svd_setup_new + * + * @param U is a 2D array of size 'm' x 'n', or a 'NULL' pointer (it + * is not calculated, then). + * @param S is a 1D array of size 'n', representing the diagonal matrix + * of the singular values of 'A'. + * @param V is a 2D array f size 'n' x 'n', or a 'NULL' pointer (it is not + * calculated, then). + * @param A is a 2D array of size 'm' x 'n'. 'A' may be modified by the + * computation depending on the mode used to create 'svd_setup' + * @param svd_setup is a previously allocated setup (by rta_setup_new). + * + */ +void +rta_svd(rta_real_t * U, rta_real_t * S, rta_real_t * V, rta_real_t * A, + const rta_svd_setup_t * svd_setup); + + +/** + * + * For an m-by-n matrix A with m >= n, the singular value + * decomposition is an m-by-n orthogonal matrix U, an n-by-n diagonal + * matrix S, and an n-by-n orthogonal matrix V so that A = U*S*V'. + * (V' is the conjugate transpose of V and only the diagonal vector of + * S is represented here.) + * + * The singular values, S[k*s_tride] are ordered so that + * S[0] >= S[s_tride] >= ... >= S[(n-1)*s_tride]. + * + * The singular value decompostion always exists, so the constructor will + * never fail. The matrix condition number and the effective numerical + * rank can be computed from the singlar values. + * + * Any array must be allocated before calling this function. + * Any 2D array is in row-major order. + * + * \see rta_svd_setup_new + * + * @param U is a 2D array of size 'm' x 'n', or a 'NULL' pointer (it + * is not calculated, then). + * @param u_stride is 'U' stride + * @param S is a 1D array of size 'n', representing the diagonal matrix + * of the singular values of 'A'. + * @param s_stride is 'S' stride + * @param V is a 2D array f size 'n' x 'n', or a 'NULL' pointer (it is not + * calculated, then). + * @param v_stride is 'V' stride + * @param A is a 2D array of size 'm' x 'n'. 'A' may be modified by the + * computation depending on the mode used to create 'svd_setup' + * @param a_stride is 'A' stride + * @param svd_setup is a previously allocated setup (by rta_setup_new). + * + */ +void +rta_svd_stride(rta_real_t * U, const int u_stride, + rta_real_t * S, const int s_stride, + rta_real_t * V, const int v_stride, + rta_real_t * A, const int a_stride, + const rta_svd_setup_t * svd_setup); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_SVD_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_window.c b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_window.c new file mode 100644 index 0000000000000000000000000000000000000000..7627616b03f5e4904a89947c0d4c31aea0b648a7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_window.c @@ -0,0 +1,300 @@ +/** + * @file rta_window.c + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Signal windowing + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rta_window.h" +#include "rta_math.h" /* M_PI, cos */ + + + +/* y = 0.5 - 0.5 * cos(2 * pi * x) */ +int rta_window_hann_weights(rta_real_t * weights_vector, + const unsigned int weights_size) +{ + int i; + int ret = 1; /* return value */ + const rta_real_t step = 2. * M_PI / weights_size; + + for(i=0; i<weights_size; i++) + { + weights_vector[i] = 0.5 - 0.5 * rta_cos(i*step); + } + + return ret; +} + +int rta_window_hann_weights_stride( + rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size) +{ + int i; + int ret = 1; /* return value */ + const rta_real_t step = 2. * M_PI / weights_size; + + for(i=0; i<weights_size*w_stride; i+=w_stride) + { + weights_vector[i] = 0.5 - 0.5 * rta_cos(i*step); + } + + return ret; +} + +void rta_window_hann_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size) +{ + int i; + const rta_real_t step = 2. * M_PI / input_size; + for(i=0; i<input_size; i++) + { + input_vector[i] *= 0.5 - 0.5 * rta_cos(i*step); + } + + return; +} + +void rta_window_hann_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size) +{ + int i; + const rta_real_t step = 2. * M_PI / input_size; + for(i=0; i<input_size*i_stride; i+=i_stride) + { + input_vector[i] *= 0.5 - 0.5 * rta_cos(i*step); + } + + return; +} + +/* y = coef + (1-coef)(0.5 - 0.5 * cos(2 * pi * x)) */ +/* raised-cosine, real hamming window if coef == 0.08 */ +int rta_window_hamming_weights(rta_real_t * weights_vector, + const unsigned int weights_size, + const rta_real_t coef) +{ + int i; + int ret = 1; /* return value */ + const rta_real_t step = 2. * M_PI / weights_size; + const rta_real_t scale = (1. - coef) * 0.5; + + for(i=0; i<weights_size; i++) + { + weights_vector[i] = coef + scale * (1. - rta_cos(i*step)); + } + + return ret; +} + +int rta_window_hamming_weights_stride( + rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size, + const rta_real_t coef) +{ + int i; + int ret = 1; /* return value */ + const rta_real_t step = 2. * M_PI / weights_size; + const rta_real_t scale = (1. - coef) * 0.5; + + for(i=0; i<weights_size*w_stride; i+=w_stride) + { + weights_vector[i] = coef + scale * (1. - rta_cos(i*step)); + } + + return ret; +} + +void rta_window_hamming_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size, + const rta_real_t coef) +{ + int i; + const rta_real_t step = 2. * M_PI / input_size; + const rta_real_t scale = (1. - coef) * 0.5; + + for(i=0; i<input_size; i++) + { + input_vector[i] *= coef + scale * (1. - rta_cos(i*step)); + } + + return; +} + +void rta_window_hamming_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size, + const rta_real_t coef) +{ + int i; + const rta_real_t step = 2. * M_PI / input_size; + const rta_real_t scale = (1. - coef) * 0.5; + + for(i=0; i<input_size*i_stride; i+=i_stride) + { + input_vector[i] *= coef + scale * (1. - rta_cos(i*step)); + } + + return; +} + + +void rta_window_apply(rta_real_t * output_vector, + const unsigned int output_size, + const rta_real_t * input_vector, + const rta_real_t * weights_vector) +{ + int i; + + for(i=0; i<output_size; i++) + { + output_vector[i] = input_vector[i] * weights_vector[i]; + } + + return; +} + +void rta_window_apply_stride( + rta_real_t * output_vector, const int o_stride, + const unsigned int output_size, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_vector, const int w_stride) +{ + int o,i,w; + + for(o=0, i=0, w=0; o<output_size*o_stride; o+=o_stride, i+=i_stride, w+=w_stride) + { + output_vector[o] = input_vector[i] * weights_vector[w]; + } + + return; +} + + +void rta_window_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size, + const rta_real_t * weights_vector) +{ + int i; + + for(i=0; i<input_size; i++) + { + input_vector[i] *= weights_vector[i]; + } + + return; +} + +void rta_window_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size, + const rta_real_t * weights_vector, const int w_stride) +{ + int i,w; + + for(i=0,w=0; i<input_size*i_stride; i+=i_stride, w+=w_stride) + { + input_vector[i] *= weights_vector[w]; + } + + return; +} + +void rta_window_rounded_apply( + rta_real_t * output_vector, const unsigned int output_size, + const rta_real_t * input_vector, + const rta_real_t * weights_vector, const unsigned int weights_size) +{ + int i; + const rta_real_t step = (rta_real_t) weights_size / (rta_real_t) output_size; + + for(i=0; i<output_size; i++) + { + output_vector[i] = input_vector[i] * weights_vector[(int)rta_round(i*step)]; + } + + return; +} + +void rta_window_rounded_apply_stride( + rta_real_t * output_vector, const int o_stride, + const unsigned int output_size, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size) +{ + int i; + const rta_real_t step = (rta_real_t) weights_size / (rta_real_t) output_size; + + for(i=0; i<output_size; i++) + { + output_vector[i] = input_vector[i] * weights_vector[(int)rta_round(i*step)]; + } + + return; +} + +void rta_window_rounded_apply_in_place( + rta_real_t * input_vector, const unsigned int input_size, + const rta_real_t * weights_vector, const unsigned int weights_size) +{ + int i; + const rta_real_t step = (rta_real_t) weights_size / (rta_real_t) input_size; + + for(i=0; i<input_size; i++) + { + input_vector[i] *= weights_vector[(int)rta_round(i*step)]; + } + + return; +} + +void rta_window_rounded_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size) +{ + int i,w; + const rta_real_t step = (rta_real_t) weights_size / (rta_real_t) input_size; + + for(i=0,w=0; i<input_size*i_stride; i+=i_stride, w+=w_stride) + { + input_vector[i] *= weights_vector[(int)rta_round(w*step)]; + } + + return; +} + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_window.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_window.h new file mode 100644 index 0000000000000000000000000000000000000000..955b78b38d89abfab5def15d6be58266df0899cb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/misc/rta_window.h @@ -0,0 +1,379 @@ +/** + * @file rta_window.h + * @author Jean-Philippe.Lambert@ircam.fr + * @date Fri Jun 15 15:29:25 2007 + * + * @brief Signal windowing + * + * @copyright + * Copyright (C) 2007 by IRCAM-Centre Georges Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_WINDOW_H_ +#define _RTA_WINDOW_H_ 1 + +#include "rta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generate a vector of weights 'weights_vector' to be applied to + * another signal vector, on the form of a von Hann window. + * + * y = 0.5 - 0.5 * cos(2 * pi * x), + * x is in [0,1] as x is scaled by ('weights_size' - 1) + * + * \see rta_window_apply + * \see rta_window_apply_in_place + * \see rta_window_rounded_apply + * \see rta_window_rounded_apply_in_place + * + * @param weights_vector size is 'weights_size' + * @param weights_size is the number of steps + * + * @return 1 on success 0 on fail + */ +int +rta_window_hann_weights(rta_real_t * weights_vector, + const unsigned int weights_size); + +/** + * Generate a vector of weights 'weights_vector' to be applied to + * another signal vector, on the form of a von Hann window. + * + * y = 0.5 - 0.5 * cos(2 * pi * x), + * x is in [0,1] as x is scaled by ('weights_size' - 1) + * + * \see rta_window_apply_stride + * \see rta_window_apply_in_place_stride + * \see rta_window_rounded_apply_stride + * \see rta_window_rounded_apply_in_place_stride + * + * @param weights_vector size is 'weights_size' + * @param w_stride is 'weights_vector' stride + * @param weights_size is the number of steps + * + * @return 1 on success 0 on fail + */ +int +rta_window_hann_weights_stride( + rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size); + +/** + * Apply a von Hann window on an 'input_vector', calculating the + * window on the fly. + * + * \see rta_window_hann_weights + * + * @param input_vector size is 'input_size' + * @param input_size is the number of points of the 'input_vector' + */ +void +rta_window_hann_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size); + +/** + * Apply a von Hann window on an 'input_vector', calculating the + * window on the fly. + * + * \see rta_window_hann_weights_stride + * + * @param input_vector size is 'input_size' + * @param i_stride is 'input_vector' stride + * @param input_size is the number of points of the 'input_vector' + */ +void +rta_window_hann_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size); + +/** + * Generate a vector of weights 'weights_vector' to be applied to + * another signal vector, on the form of a raised-cosine window. If + * 'coef' == 0.08, it is a real Hamming window. + * + * y = coef + (1-coef)(0.5 - 0.5 * cos(2 * pi * x)), + * x is in [0,1] as x is scaled by ('weights_size' - 1) + * + * \see rta_window_apply + * \see rta_window_apply_in_place + * \see rta_window_rounded_apply + * \see rta_window_rounded_apply_in_place + * + * @param weights_vector size is 'weights_size' + * @param weights_size is the number of steps + * @param coef is the raiser coefficient + * + * @return 1 on success 0 on fail + */ +int +rta_window_hamming_weights(rta_real_t * weights_vector, + const unsigned int weights_size, + const rta_real_t coef); + +/** + * Generate a vector of weights 'weights_vector' to be applied to + * another signal vector, on the form of a raised-cosine window. If + * 'coef' == 0.08, it is a real Hamming window. + * + * y = coef + (1-coef)(0.5 - 0.5 * cos(2 * pi * x)), + * x is in [0,1] as x is scaled by ('weights_size' - 1) + * + * \see rta_window_apply_stride + * \see rta_window_apply_in_place_stride + * \see rta_window_rounded_apply_stride + * \see rta_window_rounded_apply_in_place_stride + * + * @param weights_vector size is 'weights_size' + * @param w_stride is 'weights_vector' stride + * @param weights_size is the number of steps + * @param coef is the raiser coefficient + * + * @return 1 on success 0 on fail + */ +int +rta_window_hamming_weights_stride( + rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size, + const rta_real_t coef); + +/** + * Apply a Hamming window on an 'input_vector', calculating the + * window on the fly. + * + * \see rta_window_hamming_weights + * + * @param input_vector size is 'input_size' + * @param input_size is the number of points of the 'input_vector' + * @param coef is the raiser coefficient + */ +void +rta_window_hamming_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size, + const rta_real_t coef); +/** + * Apply a Hamming window on an 'input_vector', calculating the + * window on the fly. + * + * \see rta_window_hamming_weights + * + * @param input_vector size is 'input_size' + * @param i_stride is 'input_vector' stride + * @param input_size is the number of points of the 'input_vector' + * @param coef is the raiser coefficient + */ +void +rta_window_hamming_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size, + const rta_real_t coef); + +/** + * Apply any 'weights_vector' on an 'input_vector' and output the + * result as 'output_vector'. + * 'input_vector' and 'weights_vector' may not overlap. + * + * \see rta_window_apply_in_place + * + * @param output_vector size is 'output_size' + * @param output_size is the number of points of 'output_vector' + * @param input_vector size is >= 'output_size' + * @param weights_vector size is >= 'output_size' + */ +void +rta_window_apply(rta_real_t * output_vector, + const unsigned int output_size, + const rta_real_t * input_vector, + const rta_real_t * weights_vector); + +/** + * Apply any 'weights_vector' on an 'input_vector' and output the + * result as 'output_vector'. + * 'input_vector' and 'weights_vector' may not overlap. + * + * \see rta_window_apply_in_place_stride + * + * @param output_vector size is 'output_size' + * @param o_stride is 'output_vector' stride + * @param output_size is the number of points of 'output_vector' + * @param input_vector size is >= 'output_size' + * @param i_stride is 'input_vector' stride + * @param weights_vector size is >= 'output_size' + * @param w_stride is 'weights_vector' stride + */ +void +rta_window_apply_stride( + rta_real_t * output_vector, const int o_stride, + const unsigned int output_size, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_vector, const int w_stride); + +/** + * Apply any 'weights_vector' on an 'input_vector'. + * 'input_vector' and 'weights_vector' may not overlap. + * + * \see rta_window_hann_weights + * \see rta_window_hamming_weights + * + * @param input_vector size is 'input_size' + * @param input_size is the number of points of the 'input_vector' + * @param weights_vector size must be >= 'input_size'. + */ +void +rta_window_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size, + const rta_real_t * weights_vector); + +/** + * Apply any 'weights_vector' on an 'input_vector'. + * 'input_vector' and 'weights_vector' may not overlap. + * + * \see rta_window_hann_weights_stride + * \see rta_window_hamming_weights_stride + * + * @param input_vector size is 'input_size' + * @param i_stride is 'input_vector' stride + * @param input_size is the number of points of the 'input_vector' + * @param weights_vector size must be >= 'input_size'. + * @param w_stride is 'weights_vector' stride + */ +void +rta_window_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size, + const rta_real_t * weights_vector, const int w_stride); + +/** + * Apply any 'weights_vector' on an 'input_vector'. + * 'output_vector' and 'weights_vector' may not overlap. + * + * If 'input_size' != 'weights_size' then the 'weights_vector' indexes + * are scaled and rounded. The rounding error may be acceptable is + * 'weights_size' is big enough (4096 points for 12 bits resolution) + * or if 'input_size' is a multiple of 'weights_size'. + * + * \see rta_window_apply + * + * @param output_vector size is 'output_size' + * @param output_size is the number of points of the 'output_vector' + * @param input_vector size is >= 'output_size' + * @param weights_vector is the number of points of the 'input_vector' + * @param weights_size is the number of points of the 'weights_vector' + */ +void +rta_window_rounded_apply( + rta_real_t * output_vector, const unsigned int output_size, + const rta_real_t * input_vector, + const rta_real_t * weights_vector, const unsigned int weights_size); + +/** + * Apply any 'weights_vector' on an 'input_vector'. + * 'output_vector' and 'weights_vector' may not overlap. + * + * If 'input_size' != 'weights_size' then the 'weights_vector' indexes + * are scaled and rounded. The rounding error may be acceptable is + * 'weights_size' is big enough (4096 points for 12 bits resolution) + * or if 'input_size' is a multiple of 'weights_size'. + * + * \see rta_window_apply_stride + * + * @param output_vector size is 'output_size' + * @param o_stride is 'output_vector' stride + * @param output_size is the number of points of the 'output_vector' + * @param input_vector size is >= 'output_size' + * @param i_stride is 'input_vector' stride + * @param weights_vector is the number of points of the 'input_vector' + * @param w_stride is 'weights_vector' stride + * @param weights_size is the number of points of the 'weights_vector' + */ +void +rta_window_rounded_apply_stride( + rta_real_t * output_vector, const int o_stride, + const unsigned int output_size, + const rta_real_t * input_vector, const int i_stride, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size); + +/** + * Apply any 'weights_vector' on an 'input_vector'. + * 'input_vector' and 'weights_vector' may not overlap. + * + * If 'input_size' != 'weights_size' then the 'weights_vector' indexes + * are scaled and rounded. The rounding error may be acceptable is + * 'weights_size' is big enough (4096 points for 12 bits resolution) + * or if 'input_size' is a multiple of 'weights_size'. + * + * \see rta_window_apply + * + * @param input_vector size is 'input_size' + * @param input_size is the number of points of the 'input_vector' + * @param weights_vector size is 'weights_size' + * @param weights_size is the number of points of the 'weights_vector' + */ +void +rta_window_rounded_apply_in_place(rta_real_t * input_vector, + const unsigned int input_size, + const rta_real_t * weights_vector, + const unsigned int weights_size); + +/** + * Apply any 'weights_vector' on an 'input_vector'. + * 'input_vector' and 'weights_vector' may not overlap. + * + * If 'input_size' != 'weights_size' then the 'weights_vector' indexes + * are scaled and rounded. The rounding error may be acceptable is + * 'weights_size' is big enough (4096 points for 12 bits resolution) + * or if 'input_size' is a multiple of 'weights_size'. + * + * \see rta_window_apply_stride + * + * @param input_vector size is 'input_size' + * @param i_stride is 'input_vector' stride + * @param input_size is the number of points of the 'input_vector' + * @param weights_vector size is 'weights_size' + * @param w_stride is 'weights_vector' stride + * @param weights_size is the number of points of the 'weights_vector' + */ +void +rta_window_rounded_apply_in_place_stride( + rta_real_t * input_vector, const int i_stride, + const unsigned int input_size, + const rta_real_t * weights_vector, const int w_stride, + const unsigned int weights_size); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTA_WINDOW_H_ */ + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/rta_configuration.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/rta_configuration.h new file mode 100644 index 0000000000000000000000000000000000000000..b2ec62442ca24b19082103228f47ad2b975c13b2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/dependencies/rta/rta_configuration.h @@ -0,0 +1,64 @@ +/** + * @file rta_configuration.h + * @brief Custom configuration for the rta library + * + * @copyright + * Copyright (C) 2008-2014 by IRCAM – Centre Pompidou. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTA_CONFIGURATIONx_H_ +#define _RTA_CONFIGURATIONx_H_ 1 + +//#define rta_post post +#define rta_post printf + +/** fts memory allocation */ +#undef rta_malloc +#define rta_malloc malloc + +/** fts memory reallocation */ +#undef rta_realloc +#define rta_realloc realloc + +/** fts memory deallocation */ +#undef rta_free +#define rta_free free + +/** simple floating point precision */ +#undef RTA_REAL_TYPE +#define RTA_REAL_TYPE RTA_FLOAT_TYPE + +/* Apple VecLib for float and double */ +#if defined(__APPLE__) && defined(__MACH__) && \ +(RTA_REAL_TYPE == RTA_FLOAT_TYPE || RTA_REAL_TYPE == RTA_DOUBLE_TYPE) +#define RTA_USE_VECLIB 1 +#endif + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoCollection.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoCollection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..209b96b0fdf8ea518ed12700416b1a0ecc979cb8 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoCollection.cpp @@ -0,0 +1,187 @@ +/** + * @file PiPoCollection.cpp + * @author Norbert.Schnell@ircam.fr + * @author joseph.larralde@ircam.fr + * + * @brief PiPo Module Collection + * + * @copyright + * Copyright (C) 2013 - 2015 by ISMM IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PiPoCollection.h" + +#include "PiPoHost.h" + +#include "PiPoBands.h" +#include "PiPoBayesFilter.h" +#include "PiPoBiquad.h" +#include "PiPoChop.h" +#include "PiPoConst.h" +#include "PiPoDct.h" +#include "PiPoDelta.h" +#include "PiPoFft.h" +#include "PiPoFiniteDif.h" +#include "PiPoGate.h" +#include "PiPoLpc.h" +#include "PiPoLpcFormants.h" +#include "PiPoMedian.h" +#include "PiPoMel.h" +#include "PiPoMfcc.h" +#include "PiPoMoments.h" +#include "PiPoMvavrg.h" +#include "PiPoOnseg.h" +#include "PiPoPeaks.h" +#include "PiPoScale.h" +#include "PiPoSelect.h" +#include "PiPoSlice.h" +#include "PiPoSum.h" + +class PiPoPool : public PiPoModuleFactory +{ + class PiPoPoolModule : public PiPoModule + { + private: + PiPo *pipo; + std::string instanceName; + + public: + PiPoPoolModule(PiPo *pipo) { + this->pipo = pipo; + } + + PiPoPoolModule() { + if(this->pipo != NULL) { + delete this->pipo; + this->pipo = NULL; + } + } + }; + +public: + PiPoPool(bool defaultPipos = true) + { + if(defaultPipos) + { + includeDefaultPiPos(); + } + } + + ~PiPoPool() + { + /*for(pipoMap::iterator it = map.begin(); it != map.end(); ++it) + { + if(it->second != NULL) { + delete it->second; + it->second = NULL; + } + }*/ + } + + void includeDefaultPiPos() + { + include("bands", new PiPoCreator<PiPoBands>); + include("bayesfilter", new PiPoCreator<PiPoBayesFilter>); + include("biquad", new PiPoCreator<PiPoBiquad>); + include("chop", new PiPoCreator<PiPoChop>); + include("const", new PiPoCreator<PiPoConst>); + include("dct", new PiPoCreator<PiPoDct>); + include("delta", new PiPoCreator<PiPoDelta>); + include("fft", new PiPoCreator<PiPoFft>); + include("finitedif", new PiPoCreator<PiPoFiniteDif>); + include("gate", new PiPoCreator<PiPoGate>); + include("lpc", new PiPoCreator<PiPoLpc>); + include("lpcformants", new PiPoCreator<PiPoLpcFormants>); + include("median", new PiPoCreator<PiPoMedian>); + include("mel", new PiPoCreator<PiPoMel>); + include("mfcc", new PiPoCreator<PiPoMfcc>); + include("moments", new PiPoCreator<PiPoMoments>); + include("mvavrg", new PiPoCreator<PiPoMvavrg>); + include("onseg", new PiPoCreator<PiPoOnseg>); + include("peaks", new PiPoCreator<PiPoPeaks>); + include("scale", new PiPoCreator<PiPoScale>); + include("select", new PiPoCreator<PiPoSelect>); + include("slice", new PiPoCreator<PiPoSlice>); + include("sum", new PiPoCreator<PiPoSum>); + } + + void include(std::string name, PiPoCreatorBase *creator) + { + map[name] = creator; + } + + PiPo *create(unsigned int index, const std::string &pipoName, const std::string &instanceName, PiPoModule *&module) + { + pipoMap::iterator it = map.find(pipoName); + if (it == map.end()) return NULL; + PiPo *ret = it->second->create(); + module = new PiPoPoolModule(ret); + return ret; + } + +private: + typedef std::map<std::string, PiPoCreatorBase *> pipoMap; + pipoMap map; +}; + +//==========================================================// + +static PiPoPool *factory; + +void +PiPoCollection::init(bool defaultPipos) +{ + factory = new PiPoPool(defaultPipos); +} + +void +PiPoCollection::deinit() +{ + if (factory != NULL) delete factory; +} + +void +PiPoCollection::addToCollection(std::string name, PiPoCreatorBase *creator) +{ + factory->include(name, creator); +} + +PiPo * +PiPoCollection::create(std::string name) +{ + PiPoChain *chain = new PiPoChain(NULL, factory); + + if (chain->parse(name.c_str()) > 0 && chain->instantiate() && chain->connect(NULL)) + { + chain->copyPiPoAttributes(); + return static_cast<PiPo *>(chain); + } + return NULL; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoCollection.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoCollection.h new file mode 100644 index 0000000000000000000000000000000000000000..037bcf2e0adaa4da29e055219713d7919cb5b666 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoCollection.h @@ -0,0 +1,109 @@ +/** + * @file PiPoCollection.h + * @author Norbert.Schnell@ircam.fr + * @author joseph.larralde@ircam.fr + * + * @brief PiPo Module Collection + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2013 - 2015 by ISMM IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_COLLECTION_ +#define _PIPO_COLLECTION_ + +#include <map> +#include "PiPo.h" + +//============================================================================// +//============================== PiPo factory ================================// +//============================================================================// + +//------------------------------ PiPoCreatorBase +class PiPoCreatorBase +{ +public: + //PiPoCreatorBase() {} + virtual ~PiPoCreatorBase() {} + virtual PiPo *create() = 0; +}; + +//------------------------------ PiPoCreator +template<class T> +class PiPoCreator : public PiPoCreatorBase +{ +public: + PiPoCreator() {} + virtual ~PiPoCreator() {} + virtual PiPo *create() + { + return new T(NULL); + } +}; + +//============================================================================// +//============================== PiPo collection =============================// +//============================================================================// + +// interface with the outside world (uses the factory internally) + +/** + * @brief PiPoCollection class : contains all base PiPo classes + * (with ability to hide them from the outside world) + * and methods to register new PiPos and get PiPo chains + * + * \code + * + * #include "PiPoCollection.h" + * + * // example : register a new non native PiPo : + * PiPoCollection::init(); + * PiPoCollection::addToCollection("mypipo", new PiPoCreator<MyPiPo>); + * PiPo *mychain = PiPoCollection::create("slice:mypipo"); + * + * \endcode + * + */ + +class PiPoCollection +{ +public: + static void deinit(); + static void init(bool defaultPipos = true); + //static void init(std::string pipoPath = ""); + static void addToCollection(std::string name, PiPoCreatorBase *creator); + // static void addAlias(std::string alias, std::string name); ----> TODO + static PiPo *create(std::string name); +private: +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoGraph.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoGraph.h new file mode 100644 index 0000000000000000000000000000000000000000..c4ab62ce9797eca7d18a043fffeab55c0bac90b1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoGraph.h @@ -0,0 +1,495 @@ +/** + * @file PiPoGraph.h + * @author Joseph Larralde + * + * @brief PiPo dataflow graph class that parses a graph description string and instantiates + * the corresponding graph of PiPos (made of PiPoSequence and PiPoParallel instances) + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2017 by ISMM IRCAM - Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPOHOST_H_ +#define _PIPOHOST_H_ + +#include <string> +#include <vector> +#include <iostream> + +#include "PiPoSequence.h" +#include "PiPoParallel.h" +#include "PiPoHost.h" + +// TODO: roll your own Module, Factory and Op ? +// -------------------------------------------- + +// class PiPoModule { + +// }; + +// class PiPoModuleFactory { + +// }; + +// class PiPoOp { + +// }; + + + +// NB : this is a work in progress, only performs parsing at the moment +// TODO : implement actual graph instatiation. +// TODO: define error return codes for parsing + +class PiPoGraph : public PiPo { + + typedef enum PiPoGraphTypeE { + undefined = -1, leaf = 0, sequence, parallel + } PiPoGraphType; + +private: + std::string representation; + PiPoGraphType graphType; + + // parallel graphs if isParallel + // sequence of graphs otherwise (not sequence of PiPos) + // empty if leaf + std::vector<PiPoGraph> subGraphs; + + // use op if we are a leaf to parse instanceName and to hold attributes + PiPoOp op; + + PiPo *pipo; + std::vector<std::string *> attrNames; + std::vector<std::string *> attrDescrs; + PiPoModuleFactory *moduleFactory; + + // for intermediary level PiPoGraphs : these point to leaves' attrs so that + // top level PiPoGraph can add them to itself with this->addAttr + std::vector<PiPo::Attr *> attrs; + +public: + PiPoGraph(PiPo::Parent *parent, PiPoModuleFactory *moduleFactory = NULL) : + PiPo(parent) + { + this->parent = parent; + this->moduleFactory = moduleFactory; + } + + ~PiPoGraph() + { + for (unsigned int i = 0; i < attrNames.size(); i++) + { + delete attrNames[i]; + } + + for (unsigned int i = 0; i < attrDescrs.size(); i++) + { + delete attrDescrs[i]; + } + + this->clear(); + } + + void clear() + { + for (unsigned int i = 0; i < this->subGraphs.size(); ++i) + { + this->subGraphs[i].clear(); + } + + if (this->op.getPiPo() == NULL) + { + delete this->pipo; + } + else + { + this->op.clear(); + } + }; + + //======================== PARSE GRAPH EXPRESSION ==========================// + + // or use const char * ? + bool parse(std::string graphStr) { + + //=================== BASIC SYNTAX RULES CHECKING ========================// + + //========== check if we have the right number of '<' and '>' ============// + + int cnt = 0; + for (unsigned int i = 0; i < graphStr.length(); ++i) + { + if (graphStr[i] == '<') + { + cnt++; + } + else if (graphStr[i] == '>') + { + cnt--; + } + } + + if (cnt != 0) + { + return false; + } + + // TODO : add more syntax checking here ? + + //======= determine the type of graph (leaf, sequence or parallel) =======// + + unsigned int trims = 0; + while (graphStr[0] == '<' && graphStr[graphStr.length() - 1] == '>') + { + graphStr = graphStr.substr(1, graphStr.length() - 2); + trims++; + } + + this->representation = graphStr; + + // by default we are a sequence + this->graphType = sequence; + + // if we have surrounding "<...>" and first-level commas, we are a parallel + if (trims > 0) + { + int subLevelsCnt = 0; + for (unsigned int i = 0; i < graphStr.length(); ++i) + { + if (graphStr[i] == '<') + { + subLevelsCnt++; + } + else if (graphStr[i] == '>') + { + subLevelsCnt--; + } + else if (subLevelsCnt == 0 && graphStr[i] == ',') + { + this->graphType = parallel; + break; + } + } + } + + // if we don't have any sequential / parallelism symbol, then we are a leaf + if (graphStr.find("<") >= std::string::npos && + graphStr.find(">") >= std::string::npos && + graphStr.find(",") >= std::string::npos && + graphStr.find(":") >= std::string::npos) + { + this->graphType = leaf; + } + + // std::cout << representation << " " << this->graphType << std::endl; + + //====== now fill (or not) subGraphs vector according to graph type ======// + + switch (this->graphType) + { + + //========================== leaf graph, we are a single PiPo, trim spaces + case leaf: + { + // trim spaces + // TODO: trim tabs and other spaces ? + this->representation.erase( + std::remove(this->representation.begin(), this->representation.end(), ' '), + this->representation.end() + ); + + // this parses pipoName and instanceName + // keep using PiPoOp class for this instead (as in PiPoChain) ? + // ===> YES !!! DEFINITELY !!! PiPoOp manages PiPoVersion etc + // (LEAVE THIS TO PiPoOp CLASS) + + /* + size_t open = this->representation.find('('); + size_t close = this->representation.find(')'); + + if (open < std::string::npos || close < std::string::npos) { + // ok, do nothing + if (open > 0 && open < close && close == this->representation.length() - 1) { + // ok, parse + } else { + // parentheses are not in the right place + } + } + */ + + this->op.parse(this->representation.c_str()); + + // leaf string representation cannot be empty + return (graphStr.length() > 0); + } + + break; + + //================= sequence of graphs, parse according to ':', <' and '>' + case sequence: + { + int subLevelsCnt = 0; + unsigned int lastStartIndex = 0; + std::vector< std::pair<unsigned int, unsigned int> > subStrings; + + if (graphStr[0] == '<') + { + subLevelsCnt++; + } + + for (unsigned int i = 1; i < graphStr.length(); ++i) + { + if (graphStr[i] == ':' && subLevelsCnt == 0) + { + subStrings.push_back(std::pair<unsigned int, unsigned int>( + lastStartIndex, i - lastStartIndex + )); + lastStartIndex = i + 1; + } + else if (graphStr[i] == '<') + { + if (subLevelsCnt == 0) + { + subStrings.push_back(std::pair<unsigned int, unsigned int>( + lastStartIndex, i - lastStartIndex + )); + lastStartIndex = i; + } + subLevelsCnt++; + } + else if (graphStr[i] == '>') + { + subLevelsCnt--; + if (subLevelsCnt == 0) + { + subStrings.push_back(std::pair<unsigned int, unsigned int>( + lastStartIndex, i - lastStartIndex + 1 + )); + lastStartIndex = i + 1; + } + } + else if (graphStr[i] == ',' && subLevelsCnt == 0) + { + // cannot have first-level commas in a sequence + return false; + } + } + + if (graphStr[graphStr.length() - 1] != '>') + { + subStrings.push_back(std::pair<unsigned int, unsigned int>( + lastStartIndex, graphStr.length() - lastStartIndex + )); + } + + for (unsigned int i = 0; i < subStrings.size(); ++i) + { + this->subGraphs.push_back(PiPoGraph()); + PiPoGraph &g = this->subGraphs[subGraphs.size() - 1]; + + if (!g.parse(graphStr.substr(subStrings[i].first, subStrings[i].second))) + { + return false; + } + } + + return (subLevelsCnt == 0); + } + + break; + + //============================= parallel graphs, parse according to commas + case parallel: + { + int subLevelsCnt = 0; + std::vector<unsigned int> commaIndices; + + commaIndices.push_back(0); + + for (unsigned int i = 0; i < graphStr.length(); ++i) + { + if (graphStr[i] == '<') + { + subLevelsCnt++; + } + else if (graphStr[i] == '>') + { + subLevelsCnt--; + } + else if (graphStr[i] == ',' && i < graphStr.length() - 1 && subLevelsCnt == 0) + { + commaIndices.push_back(i + 1); + } + } + + commaIndices.push_back(graphStr.length() + 1); + + for (unsigned int i = 0; i < commaIndices.size() - 1; ++i) + { + this->subGraphs.push_back(PiPoGraph()); + PiPoGraph &g = this->subGraphs[this->subGraphs.size() - 1]; + unsigned int blockStart = commaIndices[i]; + unsigned int blockLength = commaIndices[i + 1] - blockStart - 1; + + if (!g.parse(graphStr.substr(blockStart, blockLength))) + { + return false; + } + } + + return (subLevelsCnt == 0); + } + + break; + + //===================================================== this never happens + default: + + break; + } + + return false; + } + + //================ ONCE EXPRESSION PARSED, INSTANTIATE OPs =================// + + bool instantiate() + { + if (this->graphType == leaf) + { + if (!this->op.instantiate(this->parent, this->moduleFactory)) + { + return false; + } + else + { + this->pipo = this->op.getPiPo(); + } + } + else if (this->graphType == sequence) + { + for (unsigned int i = 0; i < this->subGraphs.size(); ++i) + { + if (!this->subGraphs[i].instantiate()) + { + return false; + } + } + + this->pipo = new PiPoSequence(this->parent); + } + else if (this->graphType == parallel) + { + for (unsigned int i = 0; i < this->subGraphs.size(); ++i) + { + if (!this->subGraphs[i].instantiate()) + { + return false; + } + } + + this->pipo = new PiPoParallel(this->parent); + } + + return true; + } + + void connect( bool topLevel = true) + { + // add from top level to bottom level (see PiPoBasic) + if (this->graphType == sequence) + { + for (unsigned int i = 0; i < this->subGraphs.size(); ++i) + { + this->pipo->add(this->subGraphs[i].getPiPo()); + this->subGraphs[i].connect(false); + } + } + else if (this->graphType == parallel) + { + for (unsigned int i = 0; i < this->subGraphs.size(); ++i) + { + this->pipo->add(this->subGraphs[i].getPiPo()); + this->subGraphs[i].connect(false); + } + } + + if (topLevel) + { + this->setReceiver(this->pipo); + } + } + + void setReceiver(PiPo *receiver) + { + this->setReceiver(receiver); + } + + PiPoGraphType getGraphType() + { + return this->graphType; + } + + PiPo *getPiPo() + { + return this->pipo; + } + + // TODO: add an option to get PiPoAttributes only from named modules ? + void copyPiPoAttributes(bool topLevel = true) + { + for (unsigned int i = 0; i < this->subGraphs.size(); ++i) + { + if (this->subGraphs[i].getGraphType() == leaf) + { + + } + } + } + + // void print() { + // std::cout << this->representation << " " << this->graphType << std::endl; + // for (unsigned int i = 0; i < this->subGraphs.size(); ++i) { + // std::cout << " "; + // this->subGraphs[i].print(); + // } + // } +}; + +//==================== NOW WE CAN WRITE A PIPOHOST CLASS =====================// + +// class PiPoHost { + +// }; + +#endif /* _PIPOHOST_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoHost.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoHost.h new file mode 100644 index 0000000000000000000000000000000000000000..288fcc4af4298dc3902e469e99ecb4bacabed43e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoHost.h @@ -0,0 +1,409 @@ +/** + * + * @file PiPoHost.h + * @author Norbert.Schnell@ircam.fr + * + * @brief Plugin Interface for Processing Objects host class + * + * @ingroup pipoapi + * + * A PiPo host is built around the class PiPoChain that represents a sequence of + * PiPo modules piping data into each other. + * See details of the steps there. + * + * @copyright + * Copyright (C) 2012–2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _PIPO_HOST_ +#define _PIPO_HOST_ + +#include "PiPoSequence.h" +#include <string> +#include <vector> + +const float PIPO_MIN_SDK_VERSION_REQUIRED = 0.2; + +/** abstract base class for a container of a pipo module for PiPoModuleFactory + */ +class PiPoModule +{ +public: + PiPoModule(void) { }; + ~PiPoModule(void) { }; +}; + +class PiPoModuleFactory +{ +public: + PiPoModuleFactory(void) { }; + ~PiPoModuleFactory(void) { }; + + virtual PiPo *create(unsigned int index, const std::string &pipoName, const std::string &instanceName, PiPoModule *&module) = 0; +}; + +/** element of pipo chain, points to pipo pipo + */ +class PiPoOp +{ + unsigned int index; + std::string pipoName; /// pipo class name + std::string instanceName; + PiPo *pipo; + PiPoModule *module; + +public: + PiPoOp(unsigned int index = 0) : pipoName(), instanceName() + { + this->index = index; + this->pipo = NULL; + this->module = NULL; + }; + +// PiPoOp(const PiPoOp &other) : pipoName(), instanceName() +// { +// this->index = other.index; +// this->pipoName = other.pipoName; +// this->instanceName = other.instanceName; +// this->pipo = other.pipo; +// this->module = other.module; +// }; + + ~PiPoOp(void) { }; + + void setParent(PiPo::Parent *parent) + { + if(this->pipo != NULL) + this->pipo->setParent(parent); + }; + + void clear(void) + { + if(this->module != NULL) + delete this->module; + + this->module = NULL; + + if(this->pipo != NULL) + delete pipo; + + this->pipo = NULL; + }; + + /** parse one pipo name, and optional instance name in '(' ')' + */ + void parse(std::string str, size_t &pos) + { + this->clear(); + + size_t end = str.find_first_of(':', pos); + size_t open = str.find_first_of('(', pos); + size_t closed = str.find_first_of(')', pos); + + if(open < std::string::npos && closed < std::string::npos) + { + this->pipoName = str.substr(pos, open - pos); + this->instanceName = str.substr(open + 1, closed - open - 1); + } + else + { + this->pipoName = str.substr(pos, end - pos); + this->instanceName = this->pipoName; + } + + if(end < std::string::npos) + pos = end + 1; + else + pos = std::string::npos; + }; + + bool instantiate(PiPo::Parent *parent, PiPoModuleFactory *moduleFactory) + { + this->pipo = NULL; + this->module = NULL; + + if(moduleFactory != NULL) + this->pipo = moduleFactory->create(index, this->pipoName, this->instanceName, this->module); + + if(this->pipo != NULL) + { // check if version of created pipo is compatible with host + if (this->pipo->getVersion() < PIPO_MIN_SDK_VERSION_REQUIRED) + { + printf("PiPo Host ERROR: created PiPo %s version %f is smaller than minimum required version %f\n", + this->pipoName.c_str(), this->pipo->getVersion(), PIPO_MIN_SDK_VERSION_REQUIRED); + //TODO: clean up: destroy unusable pipo + return false; + } + + this->pipo->setParent(parent); + return true; + } + + return false; + }; + + void set(unsigned int index, PiPo::Parent *parent, PiPoModuleFactory *moduleFactory, const PiPoOp &other) + { + this->index = index; + this->pipoName = other.pipoName; + this->instanceName = other.instanceName; + + this->instantiate(parent, moduleFactory); + + if(this->pipo != NULL) + this->pipo->cloneAttrs(other.pipo); + }; + + PiPo *getPiPo() { return this->pipo; }; + const char *getInstanceName() { return this->instanceName.c_str(); }; + bool isInstanceName(const char *str) { return (this->instanceName.compare(str) == 0); }; +}; + +/** +A PiPo host is built around the class PiPoChain that represents a sequence of PiPo modules piping data into each other. + +The PiPoChain is setup with the following steps: + +1. parse chain definition string by calling parse() +2. instantiate each PiPoModule in the chain by calling instantiate(), using a PiPoModuleFactory +3. connect PiPos by calling PiPoSequence::connect() + +A PiPoChain is itself also a PiPo module, i.e. data processing works the same as for a simple module: +- the PiPoChain is prepared for processing by calling streamAttributes() on it. +- data is piped into the PiPoChain with the frames() method. + +The host registers as the receiver for the last PiPo module in the PiPoChain. +*/ + +class PiPoChain : public PiPoSequence //TODO: shouldn't PiPoChain just contain a member seq_ for the sequence to build, instead of inheriting? +{ + std::vector<PiPoOp> ops; + // these vectors of pointers seem necessary in copyPiPoAttributes + std::vector<std::string *> attrNames; + std::vector<std::string *> attrDescrs; + //PiPo::Parent *parent; //FIXME: remove? pipo has a parent member already! + PiPoModuleFactory *moduleFactory; + +public: + // constructor + PiPoChain(PiPo::Parent *parent, PiPoModuleFactory *moduleFactory = NULL) + : PiPoSequence(parent), ops() + { + this->parent = parent; + this->moduleFactory = moduleFactory; + }; + + // copy constructor: invoking assignment operator + PiPoChain(const PiPoChain &other) + : PiPoSequence(NULL), ops() + { + *this = other; + }; + + // assignment operator + const PiPoChain& operator=(const PiPoChain &other) + { + this->parent = other.parent; + this->moduleFactory = other.moduleFactory; + + unsigned int numOps = static_cast<unsigned int>(other.ops.size()); + this->ops.clear(); + this->ops.resize(numOps); + + for (unsigned int i = 0; i < numOps; i++) + { + this->ops[i].set(i, this->parent, this->moduleFactory, other.ops[i]); // clone pipos by re-instantiating them + this->add(this->ops[i].getPiPo(), false); // rebuild PiPoSequence to point to cloned pipos + } + + this->connect(NULL); + this->moduleFactory = NULL; + + return *this; + }; + + ~PiPoChain(void) + { + for(unsigned int i = 0; i < attrNames.size(); i++) { + delete attrNames[i]; + } + for(unsigned int i = 0; i < attrDescrs.size(); i++) { + delete attrDescrs[i]; + } + this->clear(); + }; + + + /** @name PiPoChain setup methods */ + /** @{ */ + + void clear() + { + PiPoSequence::clear(); + for(unsigned int i = 0; i < this->ops.size(); i++) + this->ops[i].clear(); + + this->ops.clear(); + }; + + + /** parse pipo chain specification from string + + creates list of PiPoOp in member ops + */ + size_t parse(const char *str) + { + std::string pipoChainStr = str; + size_t pos = 0; + + this->clear(); + + for(unsigned int i = 0; pos < std::string::npos; i++) + { + this->ops.resize(i + 1, i); + this->ops[i].parse(pipoChainStr, pos); + } + + return this->ops.size(); + }; + + /** go through list of PiPoOp in ops and instantiate PiPoModule using PiPoModuleFactory + */ + bool instantiate(void) + { + if(this->ops.size() > 0) + { + for(unsigned int i = 0; i < this->ops.size(); i++) + { + if(this->ops[i].instantiate(this->parent, this->moduleFactory)) + { // build sequence by appending modules + this->add(this->ops[i].getPiPo()); + } + else + { + this->clear(); + return false; + } + } + return true; + } + + return false; + }; + + void copyPiPoAttributes() + { + for(int iPiPo = 0; iPiPo < this->getSize(); iPiPo++) + { + PiPo *pipo = this->getPiPo(iPiPo); + + const char *instanceName = this->getInstanceName(iPiPo); + unsigned int numAttrs = pipo->getNumAttrs(); + + for(unsigned int iAttr = 0; iAttr < numAttrs; iAttr++) + { + PiPo::Attr *attr = pipo->getAttr(iAttr); + + std::string *attrName = new std::string(instanceName); + *attrName += "."; + *attrName += attr->getName(); + + std::string *attrDescr = new std::string(attr->getDescr()); + *attrDescr += " ("; + *attrDescr += instanceName; + *attrDescr += ")"; + + attrNames.push_back(attrName); + attrDescrs.push_back(attrDescr); + + this->addAttr(this, attrNames[attrNames.size() - 1]->c_str(), attrDescrs[attrDescrs.size() - 1]->c_str(), attr); + } + } + } + + /** @} PiPoChain setup methods */ + + /** @name PiPoChain query methods */ + /** @{ */ + + int getSize() + { + return static_cast<int>(this->ops.size()); + }; + + int getIndex(const char *instanceName) + { + for(unsigned int i = 0; i < this->ops.size(); i++) + { + if(this->ops[i].isInstanceName(instanceName)) + return i; + } + + return -1; + }; + + using PiPoSequence::getPiPo; // make getPiPo(unsigned int index) visible for this class PiPoChain + + PiPo *getPiPo(const char *instanceName) + { + int index = getIndex(instanceName); + + if(index >= 0) + return getPiPo(index); + + return NULL; + }; + + const char *getInstanceName(unsigned int index) + { + if(index < this->ops.size()) + return this->ops[index].getInstanceName(); + + return NULL; + }; + + /** @} PiPoChain query methods */ + + /** @name overloaded PiPo methods */ + /** @{ */ + /** @name all preparation and processing methods are inherited from PiPoSequence: + streamAttributes(), reset(), frames(), finalize() */ + /** @} end of overloaded PiPo methods */ +}; + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoModule.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoModule.h new file mode 100644 index 0000000000000000000000000000000000000000..7adac628508a7c81013bb3e2fb5545ada25bcc42 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/PiPoModule.h @@ -0,0 +1,52 @@ +/** + * @file PiPoModule.h + * @author Riccardo Borghesi + * + * @brief extension of PiPo for use in host apps + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2012-2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_MODULE_ +#define _PIPO_MODULE_ + +#include "PiPo.h" +#include "PiPoCollection.h" + +#define PIPO_MODULE_CLASS(pipoName, pipoClass) \ + extern "C" const char *getPiPoName(void); \ + extern "C" PiPoCreatorBase *getPiPoCreator(); \ + const char *getPiPoName() { return pipoName; }\ + PiPoCreatorBase *getPiPoCreator() { return new PiPoCreator<pipoClass>; } + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/mimo_host.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/mimo_host.h new file mode 100644 index 0000000000000000000000000000000000000000..063c7325fd4f21ce998734d56ea57298de2517f2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/host/mimo_host.h @@ -0,0 +1,63 @@ + +#include "../PiPoHost.h" + +/* + + every mimo module inherits the basic stream description and data + passing methods (streamAttributes() and frames()) from PiPo, but + ignores real-time oriented methods (segment()), and adds iteration + for training. + */ + +class mimo_host : public PiPoChain +{ + /* for mimo, the streamAttributes() method should give the size of the input data as maxframes */ + + /* push data through mimo modules + */ + int run_training (PiPoValue *indata, int numframes) + { + int itercount = 0; + size = width_ * height_; + + // first iteration on imput data, modules output passed to our mimo_receiver + int status = iterate(0, indata, numframes); + + while ((this->maxiter() == 0 || itercount < this->maxiter()) && status == 0) + { + itercount++; + status = iterate(itercount, indata, numframes); + } + } + + int iterate (int itercount, PiPoValue *data, numframes) + { + int status = 0; + + for (int buf = 0; buf < numbuffers; buf++) + for (int track = 0; track < numtracks; track++) + if ((status = getHead()->train(itercount, buf, track, numframes, data, timetags, varsize)) != 0) + return status; + + return status; + } +} + + +/* + reveives data iterated upon by training mimo modules + */ +class mimo_receiver : mimo +{ + PiPoValue *outputdata_; + + int frames (PiPoValue *values) + { + outputdata_ = values; + } + + // store or merge input data transformed by one iteration of training + int train () + { + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPo.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPo.h new file mode 100644 index 0000000000000000000000000000000000000000..db48e1f122281925b4005d07c715b1464a1a40f7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPo.h @@ -0,0 +1,1463 @@ +/** + * @file PiPo.h + * @author Norbert.Schnell@ircam.fr + * + * @brief Plugin Interface for Processing Objects + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2012–2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_ +#define _PIPO_ + +#include <string> +#include <vector> +#include <functional> +#include <cstring> +#include <cstdio> + +#include <typeinfo> +#include <map> + +#ifdef WIN32 +#define strcasecmp _stricmp +#define M_PI 3.14159265358979323846264338328 /**< pi */ +#endif + +//TODO: unify with maxpipohost.h +#define PIPO_MAX_LABELS 1024 + +#ifndef PIPO_SDK_VERSION +#define PIPO_SDK_VERSION 0.2 + +#endif + +typedef float PiPoValue; + + +struct PiPoStreamAttributes +{ + int hasTimeTags; + double rate; + double offset; + unsigned int dims[2]; // width, height (by pipo convention) + const char **labels; + unsigned int numLabels; + bool hasVarSize; + double domain; + unsigned int maxFrames; + int labels_alloc; // < allocated size of labels, -1 for no (outside) allocation + + PiPoStreamAttributes (int numlabels = -1) + { + init(numlabels); + } + + PiPoStreamAttributes (bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + this->hasTimeTags = hasTimeTags; + this->rate = rate; + this->offset = offset; + this->dims[0] = width; + this->dims[1] = height; + this->labels = labels; + this->numLabels = width; + this->labels_alloc = -1; // signals external memory + this->hasVarSize = hasVarSize; + this->domain = domain; + this->maxFrames = maxFrames; + } + + void init (int _numlab = -1) + { + this->hasTimeTags = false; + this->rate = 1000.0; + this->offset = 0.0; + this->dims[0] = 1; // width + this->dims[1] = 1; // height + this->labels = NULL; + this->numLabels = 0; + this->labels_alloc = _numlab; + this->hasVarSize = false; + this->domain = 0.0; + this->maxFrames = 1; + + if (_numlab >= 0) + labels = new const char *[_numlab]; + }; + + ~PiPoStreamAttributes() + { + if (labels && labels_alloc >= 0) + delete [] labels; + }; + + /** append string pointer array to labels array + */ + void concat_labels (const char **_labels, unsigned int _width) + { + if (this->labels_alloc < 0) + { + printf("Warning: PiPoStreamAttributes::concat_labels: can't concat %d labels to char ** with %d labels allocated from the outside\n", _width, this->numLabels); + _width = 0; + } + + if (this->numLabels + _width > this->labels_alloc) + { + printf("Warning: PiPoStreamAttributes::concat_labels: label overflow prevented (trying to concat %d to %d used of %d)\n", _width, this->numLabels, this->labels_alloc); + _width = this->labels_alloc - this->numLabels; + } + + if (_labels != NULL) + memcpy(this->labels + this->numLabels, _labels, _width * sizeof(const char *)); + else + for (unsigned int i = 0; i < _width; i++) + //TODO: invent numbered column, beware of memory! + this->labels[i + this->numLabels] = "unnamed"; + + this->numLabels += _width; + } + + char *to_string (char *str, int len) const + { + snprintf(str, len, + "hasTimeTags\t= %d\n" + "rate\t\t\t= %f\n" + "offset\t\t= %f\n" + "width\t\t= %d\n" + "height\t\t= %d\n" + "labels\t\t= %s...\n" + "labels_alloc\t= %d\n" + "hasVarSize\t= %d\n" + "domain\t\t= %f\n" + "maxFrames\t= %d\n", + (int) hasTimeTags, rate, offset, dims[0], dims[1], + labels && numLabels > 0 ? labels[0] : "n/a", labels_alloc, + (int) hasVarSize, domain, maxFrames); + return str; + } +}; + + +class PiPo +{ + +/** @mainpage + +PiPo is a simple plugin API for modules processing streams of multi-dimensional data such as audio, audio descriptors, or gesture and motion data. The current version of the interface is limited to unary operations. Each PiPo module receives and produces a single stream. The elements of a stream are time-tagged or regularly sampled scalars, vectors, or two-dimensional matrices. + +More information http://ismm.ircam.fr/PiPo + +\section sec_api PiPo API Overview + +The PiPo API consists of an abstract class of a few virtual methods for propagating stream attributes (see below), frames, and additional processing control through a series of modules: + +- Propagating stream attributes +- Propagating frames +- Reset stream processing +- Finalize stream processing +- Propagate the change of a parameter requiring redefining the output stream attributes + + +\subsection sec_impl Implementation of a New PiPo Module + +The minimal module must derive from the class PiPo and implement at least the \ref streamAttributes and \ref frames methods: + +- In \ref streamAttributes, all initialisation can be done, as all input stream parameters (attributes) are known. The output stream parameters are passed on to the receiving module via \ref propagateStreamAttributes. +- In \ref frames, only data processing and, when needed, buffering should be done. Output frames are passed on with \ref propagateFrames. + +If the module can produce additional output data after the end of the input data, it must implement \ref finalize, from within which more calls to \ref propagateFrames can be made, followed by a mandatory call to \ref propagateFinalize. + +If the module keeps internal state or buffering, it should implement the \ref reset method to put itself into a clean state. + +The utility function \ref signalError can be used to pass an error message to the host. + +The utility function \ref signalWarning can be used to pass a warning message to the host. + + +\subsection sec_attr Module Attributes or Parameters + +The template class PiPo::Attr permits to define scalar, enum, or variable or fixed size vector attributes of a pipo module that are exposed to the host environment. + +The are initialised in the module constructor with a short name, a description, a flag if a change of value means the fundamental stream parameters must be reset (if true, \ref streamAttributes will be called again for the whole chain), and a default value. + +Their value can be queried in \ref streamAttributes or \ref frames (in real-time hosts, an attributes value can change over time) with PiPo::Attr::get(). + +\subsection sec_example Example of a Minimal PiPo Module + + +\code + +class PiPoGain : public PiPo +{ +private: + std::vector<PiPoValue> buffer; + +public: + PiPoScalarAttr<double> factor; + + PiPoGain (Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + factor(this, "factor", "Gain Factor", false, 1.0) + { } + + ~PiPoGain (void) + { } + + int streamAttributes (bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int height, + const char **labels, bool hasVarSize, + double domain, unsigned int maxFrames) + { + // A general pipo can not work in place, we need to create an output buffer + buffer.resize(width * height * maxFrames); + + return propagateStreamAttributes(hasTimeTags, rate, offset, width, height, + labels, hasVarSize, domain, maxFrames); + } + + int frames (double time, double weight, PiPoValue *values, + unsigned int size, unsigned int num) + { + double f = factor.get(); // get gain factor here, as it could change while running + PiPoValue *ptr = &buffer[0]; + + for (unsigned int i = 0; i < num; i++) + { + for (unsigned int j = 0; j < size; j++) + ptr[j] = values[j] * f; + + ptr += size; + values += size; + } + + return propagateFrames(time, weight, &buffer[0], size, num); + } +}; +\endcode + + +\section sec_api_details PiPo API Details + +\subsection sec_stream_attr PiPo Stream Attributes + +PiPo streams are a sequences of frames characterized by a set of attributes. A PiPo module defines the attributes of its output stream when receiving the attributes of the input stream. + +Each module can configure its internal state depending on the attributes of the input stream (e.g. memory allocation and pre-calculated state variables) before propagating its output stream attributes to the next module. + +This way, the attributes of the input stream are propagated through a series of PiPo modules before starting the actual stream processing. + +In summary, a PiPo stream is described by the following attributes: + +- a boolean representing whether the elements of the stream are time-tagged +- frame rate (highest average rate for time-tagged streams) +- lag of the output stream relative to the input +- frame width (also number of channels or data matrix columns) +- frame height (or number of matrix rows) +- labels (for the frame channels or columns) +- a boolean representing whether the frames have a variable height (respecting the given frame height as maximum) +- extent of a frame in the given domain (e.g. duration or frequency range) +- maximum number of frames in a block exchanged between two modules + +*/ + + +public: + class Attr; + template<class, std::size_t> class AttrArray; // declare this helper template as PiPo::AttrArray + + /*********************************************** + * + * PiPo Parent + * TODO: rename PiPoHost ? + */ + + class Parent + { + public: + /** called by pipo when an attribute with "changesstream" is set */ + virtual void streamAttributesChanged(PiPo *pipo, PiPo::Attr *attr) { }; + + /** called by pipo to signal error in parameters */ + virtual void signalError(PiPo *pipo, std::string errorMsg) { }; + + /** called by pipo to signal warning in parameters */ + virtual void signalWarning(PiPo *pipo, std::string errorMsg) { }; + }; + +protected: + Parent *parent; + std::vector<PiPo *> receivers; /**< list of receivers */ + +private: + std::vector<Attr *> attrs; /**< list of attributes */ +#if __cplusplus >= 201103L && !defined(WIN32) + constexpr static const float sdk_version = PIPO_SDK_VERSION; /**< pipo SDK version (for inspection) */ +#endif + +public: + PiPo(Parent *parent, PiPo *receiver = NULL) + : receivers(), attrs() + { + this->parent = parent; + + if (receiver != NULL) + this->receivers.push_back(receiver); + }; + + PiPo(const PiPo &other) + { + this->parent = other.parent; + } + + virtual ~PiPo(void) { }; + + /** get version of SDK as a major.minor float (so that host can + * check if a pipo was compiled with correct version of PiPo.h) + */ +#ifdef PIPO_TESTING + virtual float getVersion() // only for unit tests: allow to override version to simulate an out-of-date pipo module +#else + static float getVersion() +#endif + { +#if __cplusplus >= 201103L && !defined(WIN32) + printf("pipo::getVersion -> %f\n", PiPo::sdk_version); + return PiPo::sdk_version; +#else + printf("pipo::getVersion -> %f\n", PIPO_SDK_VERSION); + return PIPO_SDK_VERSION; +#endif + }; + + /** + * @brief Sets PiPo parent. + * + * @param parent PiPo parent + */ + virtual void setParent(Parent *parent) { this->parent = parent; }; + + /** + * @brief Propagates a module's output stream attributes to its receiver. + * + * This method is called in the streamAttributes() method of a PiPo module. + * + * @param hasTimeTags a boolean representing whether the elements of the stream are time-tagged + * @param rate the frame rate (highest average rate for time-tagged streams) + * @param offset the lag of the output stream relative to the input + * @param width the frame width (also number of channels or data matrix columns) + * @param height the frame height (or number of matrix rows) + * @param labels optional labels for the frames' channels or columns + * @param hasVarSize a boolean representing whether the frames have a variable height (respecting the given frame height as maximum) + * @param domain extent of a frame in the given domain (e.g. duration or frequency range) + * @param maxFrames maximum number of frames in a block exchanged between two modules + * @return used as return value of the calling method + */ + int propagateStreamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + int ret = 0; + + for (unsigned int i = 0; i < this->receivers.size(); i++) + { + ret = this->receivers[i]->streamAttributes(hasTimeTags, rate, offset, width, height, labels, hasVarSize, domain, maxFrames); + + if (ret < 0) + break; + } + + return ret; + }; + + /** + * @brief Propagates the reset control event. + * + * This method is called in the reset() method of a PiPo module. + * + * @return used as return value of the calling method + */ + int propagateReset(void) + { + int ret = -1; + + for (unsigned int i = 0; i < this->receivers.size(); i++) + { + ret = this->receivers[i]->reset(); + + if (ret < 0) + break; + } + + return ret; + } + + /** + * @brief Propagates a module's output frames to its receiver. + * + * This method is called in the frames() method of a PiPo module. + * + * @param time time-tag for a single frame or a block of frames + * @param weight weight for this frame (currently unused) + * @param values interleaved frames values, row by row (interleaving channels or columns), frame by frame + * @param size total size of each frame (number of values = width * height) + * @param num number of frames + * @return used as return value of the calling method + */ + int propagateFrames(double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { + int ret = -1; + + for (unsigned int i = 0; i < this->receivers.size(); i++) + { + ret = this->receivers[i]->frames(time, weight, values, size, num); + + if (ret < 0) + break; + } + + return ret; + } + + /** + * @brief Propagates the finalize control event. + * + * This method is called in the finalize() method of a PiPo module. + * + * @return used as return value of the calling method + */ + int propagateFinalize(double inputEnd) + { + int ret = -1; + + for (unsigned int i = 0; i < this->receivers.size(); i++) + { + ret = this->receivers[i]->finalize(inputEnd); + + if (ret < 0) + break; + } + + return ret; + } + + /** + * @brief Gets a PiPo modules receiver (call only by the PiPo host) + * + * @return receiver PiPo module receiving this module's output stream + */ + PiPo *getReceiver(unsigned int index = 0) + { + if (index < this->receivers.size()) + return this->receivers[index]; + + return NULL; + }; + + /** + * @brief Sets a PiPo modules receiver (call only by the PiPo host) + * + * @param receiver PiPo module receiving this module's output stream + * @param add receiver (versus clear and set first) + */ + virtual void setReceiver(PiPo *receiver, bool add = false) + { + if (add) + { + if (receiver != NULL) + this->receivers.push_back(receiver); + } + else + { + this->receivers.clear(); + + if (receiver != NULL) + this->receivers.push_back(receiver); + }; + } + + /** + * @brief Configures a PiPo module according to the input stream attributes and propagate output stream attributes + * + * PiPo module: + * Any implementation of this method requires a propagateStreamAttributes() method call and returns its return value, typically like this: + * + * \code + * return this->propagateStreamAttributes(hasTimeTags, rate, offset, width, height, labels, hasVarSize, domain, maxFrames); + * \endcode + * + * PiPo host: + * A terminating receiver module provided by a PiPo host handles the final output stream attributes and usally returns 0. + * + * @param hasTimeTags a boolean representing whether the elements of the stream are time-tagged + * @param rate the frame rate (highest average rate for time-tagged streams, sample rate for audio input) + * @param offset the lag of the output stream relative to the input + * @param width the frame width (number of channels for audio or data matrix columns) + * @param height the frame height (or number of matrix rows, always 1 for audio) + * @param labels optional labels for the frames' channels or columns (can be NULL) + * @param hasVarSize a boolean representing whether the frames have a variable height (respecting the given frame height as maximum) + * @param domain extent of a frame in the given domain (e.g. duration or frequency range) + * @param maxFrames maximum number of frames in a block exchanged between two modules (window size for audio) + * @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + virtual int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) = 0; + + /** + * @brief Resets processing (optional) + * + * PiPo module: + * Any implementation of this method requires a propagateReset() method call and returns its return value. + * + * PiPo host: + * A terminating receiver module provided by a PiPo host usally simply returns 0. + * + * @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + virtual int reset(void) + { + return this->propagateReset(); + }; + + /** + * @brief Processes a single frame or a block of frames + * + * PiPo module: + * An implementation of this method may call propagateFrames(), typically like this: + * + * \code + * return this->propagateFrames(time, weight, values, size, num); + * \endcode + * + * PiPo host: + * A terminating receiver module provided by a PiPo host handles the received frames and usally returns 0. + * + * @param time time-tag for a single frame or a block of frames + * @param weight weight associated to frame or block + * @param values interleaved frames values, row by row (interleaving channels or columns), frame by frame + TODO: should be const!!! + * @param size total size of each of all frames (size = number of elements = width * height = number of channels for audio) + * @param num number of frames (number of samples for audio input) + * @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + virtual int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) = 0; + + /** + * @brief Signals segment start or end + * + * PiPo module: + * An implementation of this method calls propagateFrames() at the end of the segment. + * + * In the case of two sucessive calls to segment(), the second call implitly ends the last segment. + * + * If the module did not receive any frames - at all or since the last segment end -, the method should + * return 0 to the call segment(0.0, end) without calling propagateFrames(). + * This permits the host to check whether a module implements the segment method or not. + * + * \code + + if(this->started) + { + // do what is to be done to finalize the segment description + this->propagateFrames(time, weight, values, size, num); + this->started = false; + } + + if(start) + { + // do what is to be done to initialize the segment description + } + + return 0; + + * \endcode + * + * @param time time of segment start of end + * @param start flag, true for segment start, false for segment end + * @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + virtual int segment(double time, bool start) { return -1; }; + + /** + * @brief Finalizes processing (optinal) + * + * PiPo module: + * Any implementation of this method requires a propagateFinalize() method call and returns its return value. + * + * PiPo host: + * A terminating receiver module provided by a PiPo host usally simply returns 0. + * + * @param inputEnd end time of the finalized input stream + * @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + virtual int finalize(double inputEnd) + { + return this->propagateFinalize(inputEnd); + }; + + void streamAttributesChanged(Attr *attr) + { + if (this->parent != NULL) + this->parent->streamAttributesChanged(this, attr); + } + + /** signal error message to be output by the host + */ + void signalError(std::string errorMsg) + { + if (this->parent != NULL) + this->parent->signalError(this, errorMsg); + else + printf("PiPo::signalError (not parent): %s\n", errorMsg.c_str()); + } + + /** signal warning message to be output by the host + */ + void signalWarning(std::string errorMsg) + { + if (this->parent != NULL) + this->parent->signalWarning(this, errorMsg); + else + printf("PiPo::signalWarning (not parent): %s\n", errorMsg.c_str()); + } + + + + /*********************************************** + * + * PiPo Attributes + * + */ +public: + enum Type { Undefined, Bool, Enum, Int, Float, Double, String }; + + // dummy enum used for specialization of templates + enum Enumerate { }; + + // meta-type a la Max : + class Atom + { + private: + PiPo::Type type; + union _data { + const char *str; + double dbl; + int itg; + } data; + public: + Atom(const char *s) { this->type = String; this->data.str = s; } + Atom(double d) { this->type = Double; this->data.dbl = d; } + Atom(int i) { this->type = Int; this->data.itg = i; } + friend bool operator==(Atom &at1, Atom &at2) + { + return ((at1.isNumber() && at2.isNumber() && at1.getDouble() == at2.getDouble()) + || (at1.type == String && at1.type == at2.type && strcmp(at1.getString(), at2.getString()) == 0)); + } + friend bool operator!=(Atom &at1, Atom &at2) + { + return !(at1 == at2); + } + bool isNumber() { return (type == Int || type == Double); } + bool isString() { return type == String; } + PiPo::Type getType() { return type; } + int getInt() { return ((type == Int) ? this->data.itg : ((type == Double) ? (int)(this->data.dbl) : 0)); } + double getDouble() { return ((type == Double) ? this->data.dbl : ((type == Int) ? (double)(this->data.itg) : 0.)); } + const char * getString() { return ((type == String) ? this->data.str : ""); } + }; + + class Attr + { + private: + PiPo *pipo; /**< owner PiPo */ + unsigned int index; + const char *name; /**< attribute name */ + const char *descr; /**< short description */ + enum Type type; + bool changesStream; + + public: + /** + * PiPo attribute base class + */ + Attr(PiPo *pipo, const char *name, const char *descr, const std::type_info *type, bool changesStream) + { + this->pipo = pipo; + this->index = static_cast<unsigned int>(pipo->attrs.size()); + this->name = name; + this->descr = descr; + + if (type == &typeid(bool)) + this->type = Bool; + else if (type == &typeid(enum Enumerate)) + this->type = Enum; + else if (type == &typeid(int)) + this->type = Int; + else if (type == &typeid(float)) + this->type = Float; + else if (type == &typeid(double)) + this->type = Double; + else if (type == &typeid(std::string) || type == &typeid(const char *)) + this->type = String; + else + this->type = Undefined; + + this->changesStream = changesStream; + + pipo->attrs.push_back(this); + }; + + ~Attr(void) { }; + + void setIndex(unsigned int index) { this->index = index; }; + void setName(const char *name) { this->name = name; }; + void setDescr(const char *descr) { this->descr = descr; }; + + unsigned int getIndex(void) { return this->index; }; + const char *getName(void) { return this->name; }; + const char *getDescr(void) { return this->descr; }; + enum Type getType(void) { return this->type; }; + bool doesChangeStream(void) { return this->changesStream; }; + + virtual void clone(Attr *other) = 0; + + virtual unsigned int setSize(unsigned int size) = 0; + virtual unsigned int getSize(void) = 0; + + virtual void set(unsigned int i, int val, bool silently = false) = 0; + virtual void set(unsigned int i, double val, bool silently = false) = 0; + virtual void set(unsigned int i, const char *val, bool silently = false) = 0; + virtual int getInt(unsigned int i) = 0; + virtual double getDbl(unsigned int i) = 0; + virtual const char *getStr(unsigned int i) = 0; + + virtual std::vector<const char *> *getEnumList(void) { return NULL; }; + + void changed(bool silently = false) { if (!silently && this->changesStream) this->pipo->streamAttributesChanged(this); }; + void rename(const char *name) { this->name = name; }; + }; + + /** + * PiPo enumerator attribute base class + */ + class EnumAttr : public Attr + { + struct strCompare : public std::binary_function<const char *, const char *, bool> { + bool operator() (const char *str1, const char *str2) const { return std::strcmp(str1, str2) < 0; } + }; + + std::vector<const char *>enumList; + std::vector<const char *>enumListDoc; + std::map<const char *, unsigned int, strCompare> enumMap; + + public: + EnumAttr(PiPo *pipo, const char *name, const char *descr, const std::type_info *type, bool changesStream) : + Attr(pipo, name, descr, type, changesStream), + enumList(), enumListDoc(), enumMap() + { + }; + + void addEnumItem(const char *item, const char *doc = "undocumented") + { + unsigned int idx = static_cast<unsigned int>(this->enumList.size()); + + this->enumList.push_back(item); + this->enumListDoc.push_back(doc); + this->enumMap[item] = idx; + }; + + std::vector<const char *> *getEnumList(void) + { + return &this->enumList; + }; + + int getEnumIndex(const char *tag) + { + if (tag != NULL && this->enumMap.find(tag) != this->enumMap.end()) + return this->enumMap[tag]; + + return -1; + }; + + const char *getEnumTag(unsigned int idx) + { + if (idx < this->enumList.size()) + return this->enumList[idx]; + + return NULL; + }; + + protected: + int clipEnumIndex(int index) + { + if (index < 0) + index = 0; + else if (index >= static_cast<int>(this->enumList.size())) + index = static_cast<int>(this->enumList.size() - 1); + + return index; + }; + }; + + /** + * @brief att attribute + */ + void addAttr(PiPo *pipo, const char *name, const char *descr, Attr *attr, bool clear = false) + { + if (clear) + this->attrs.clear(); + + /* overwrite index, name, and description */ + attr->setIndex(static_cast<unsigned int>(pipo->attrs.size())); + attr->setName(name); + attr->setDescr(descr); + + /* add to attr list */ + this->attrs.push_back(attr); + }; + + /** + * @brief Gets PiPo attribute by index + * + * @param index attribute index + * @return reference to PiPo attribute (NULL for invalid attribute index) + */ + Attr *getAttr(unsigned int index) + { + if (index < this->attrs.size()) + return this->attrs[index]; + + return NULL; + }; + + /** + * @brief Gets PiPo attribute by name + * + * @param name attribute name + * @return reference to PiPo attribute (NULL for invalid attribute name) + */ + Attr *getAttr(const char *name) + { + for (unsigned int i = 0; i < this->attrs.size(); i++) + { + if (strcasecmp(this->attrs[i]->getName(), name) == 0) + return this->attrs[i]; + } + + return NULL; + }; + + /** + * @brief Gets PiPo attribute by qualified name + * + * @param piponame pipo module name in pipo chain + * @param name attribute name + * @return reference to PiPo attribute (NULL for invalid attribute name) + */ + Attr *getAttr(const char *piponame, const char *name) + { + std::string qname(piponame); + + qname += "."; + qname += name; + + return getAttr(qname.c_str()); + }; + + bool setAttr(unsigned int index, int value, bool silently = false) + { + Attr *attr = getAttr(index); + + if (attr != NULL) + { + attr->set(0, value, silently); + + return true; + } + + return false; + } + + bool setAttr(unsigned int index, int *values, unsigned int numValues, bool silently = false) + { + Attr *attr = getAttr(index); + + if (attr != NULL) + { + unsigned int size = attr->getSize(); + + if (numValues > size) + numValues = size; + + for (unsigned int i = 0; i < numValues; i++) + attr->set(i, values[i], silently); + + return true; + } + + return false; + } + + bool setAttr(unsigned int index, double val, bool silently = false) + { + Attr *attr = getAttr(index); + + if (attr != NULL) + { + attr->set(0, val, silently); + + return true; + } + + return false; + } + + bool setAttr(unsigned int index, double *values, unsigned int numValues, bool silently = false) + { + Attr *attr = getAttr(index); + + if (attr != NULL) + { + unsigned int size = attr->getSize(); + + if (numValues > size) + numValues = size; + + for (unsigned int i = 0; i < numValues; i++) + attr->set(i, values[i], true); + + attr->changed(silently); + + return true; + } + + return false; + } + + /** + * @brief Gets number of attributes + * + * @return number of attributes + */ + unsigned int getNumAttrs(void) + { + return static_cast<unsigned int>(this->attrs.size()); + }; + + /** + * @brief Copies current parent and attributes values + * + * @param other PiPo to clone + */ + void cloneAttrs(PiPo *other) + { + for (unsigned int i = 0; i < other->attrs.size(); i++) + this->attrs[i]->clone(other->attrs[i]); + }; + + /** + * @brief Copies current value(s) of given attribute + * + * @param attr attribute to clone from + */ + void cloneAttr(PiPo::Attr *attr) + { + unsigned int index = attr->getIndex(); + + this->attrs[index]->clone(attr); + }; +}; + + + +/*********************************************** + * + * Scalar Attribute + * + */ +template <typename TYPE> +class PiPoScalarAttr : public PiPo::Attr +{ +private: + TYPE value; + +public: + PiPoScalarAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, TYPE initVal = (TYPE)0) : + Attr(pipo, name, descr, &typeid(TYPE), changesStream) + { + this->value = initVal; + } + + void set(TYPE value, bool silently = false) { this->value = value; this->changed(silently); }; + TYPE get(void) { return this->value; }; + + void clone(Attr *other) { this->value = (dynamic_cast<PiPoScalarAttr<TYPE> *>(other))->value; }; + + unsigned int setSize(unsigned int size) { return this->getSize(); }; + unsigned int getSize(void) { return 1; }; + + void set(unsigned int i, int val, bool silently = false) { if(i == 0) this->value = (TYPE)val; this->changed(silently); }; + void set(unsigned int i, double val, bool silently = false) { if(i == 0) this->value = (TYPE)val; this->changed(silently); }; + void set(unsigned int i, const char *val, bool silently = false) { }; + + int getInt(unsigned int i = 0) { return (int)this->value; }; + double getDbl(unsigned int i = 0) { return (double)this->value; }; + const char *getStr(unsigned int i = 0) { return NULL; }; +}; + +template <> +class PiPoScalarAttr<const char *> : public PiPo::Attr +{ +private: + const char * value; + +public: + PiPoScalarAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, const char * initVal = (const char *)0) : + Attr(pipo, name, descr, &typeid(const char *), changesStream) + { + this->value = initVal; + } + + void set(const char * value) { this->value = value; }; + const char *get(void) { return this->value; }; + + void clone(Attr *other) { *this = *(static_cast<PiPoScalarAttr<const char *> *>(other)); }; + + unsigned int setSize(unsigned int size) { return this->getSize(); }; + unsigned int getSize(void) { return 1; }; + + void set(unsigned int i, int val, bool silently = false) { }; + void set(unsigned int i, double val, bool silently = false) { }; + void set(unsigned int i, const char *val, bool silently = false) { if(i == 0) this->value = val; this->changed(silently); }; + + int getInt(unsigned int i = 0) { return 0; }; + double getDbl(unsigned int i = 0) { return 0; }; + const char *getStr(unsigned int i = 0) { return this->value; }; +}; + +template <> +class PiPoScalarAttr<enum PiPo::Enumerate> : public PiPo::EnumAttr +{ +private: + unsigned int value; + +public: + PiPoScalarAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, unsigned int initVal = NULL) : + EnumAttr(pipo, name, descr, &typeid(enum PiPo::Enumerate), changesStream) + { + this->value = initVal; + }; + + void set(unsigned int value, bool silently = false) { this->value = clipEnumIndex(value); this->changed(silently); }; + void set(const char *value, bool silently = false) { this->value = this->getEnumIndex(value); this->changed(silently); }; + unsigned int get(void) { return this->value; }; + + void clone(Attr *other) { this->value = (dynamic_cast<PiPoScalarAttr<enum PiPo::Enumerate> *>(other))->value; }; + + unsigned int setSize(unsigned int size) { return this->getSize(); }; + unsigned int getSize(void) { return 1; }; + + void set(unsigned int i, int val, bool silently = false) { if(i == 0) this->value = clipEnumIndex((unsigned int)val); this->changed(silently); }; + void set(unsigned int i, double val, bool silently = false) { if(i == 0) this->value = clipEnumIndex((unsigned int)val); this->changed(silently); }; + void set(unsigned int i, const char *val, bool silently = false) { if(i == 0) this->value = getEnumIndex(val); this->changed(silently); }; + + int getInt(unsigned int i = 0) { return (int)this->value; }; + double getDbl(unsigned int i = 0) { return (double)this->value; }; + const char *getStr(unsigned int i = 0) { return this->getEnumTag(this->value); }; +}; + +/*********************************************** + * + * Fixed Size Array Attribute + * + */ +/* waiting for C++11 */ +template< class TYPE, std::size_t SIZE> +class PiPo::AttrArray +{ + TYPE values[SIZE]; + static const int size = SIZE; + +public: + TYPE const& operator [] (unsigned int index) const { return this->values[index]; }; + TYPE& operator [] (unsigned int index) { return &this->values[index]; }; +}; + +template <typename TYPE, unsigned int SIZE> +class PiPoArrayAttr : public PiPo::Attr, public PiPo::AttrArray<TYPE, SIZE> +{ +public: + PiPoArrayAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, TYPE initVal = (TYPE)0) : + Attr(pipo, name, descr, &typeid(TYPE), changesStream), + PiPo::AttrArray<TYPE, SIZE>() + { + for (unsigned int i = 0; i < SIZE; i++) + (*this)[i] = initVal; + } + void clone(Attr *other) { *(dynamic_cast<PiPo::AttrArray<TYPE, SIZE> *>(this)) = *(dynamic_cast<PiPo::AttrArray<TYPE, SIZE> *>(other)); }; + + unsigned int setSize(unsigned int size) { return this->getSize(); }; + unsigned int getSize(void) { return SIZE; } + + void set(unsigned int i, int val, bool silently = false) + { + if (i < SIZE) + (*this)[i] = (TYPE)val; + + this->changed(silently); + }; + + void set(unsigned int i, double val, bool silently = false) + { + if (i < SIZE) + (*this)[i] = (TYPE)val; + + this->changed(silently); + }; + + void set(unsigned int i, const char *val, bool silently = false) { }; + + int getInt(unsigned int i) + { + if (i >= SIZE) + i = SIZE - 1; + + return (int)(*this)[i]; + }; + + double getDbl(unsigned int i) + { + if (i >= SIZE) + i = SIZE - 1; + + return (double)(*this)[i]; + }; + + const char *getStr(unsigned int i) + { + if (i < SIZE) + i = SIZE - 1; + + return (const char *)(*this)[i]; + }; +}; + +template <unsigned int SIZE> +class PiPoArrayAttr<enum PiPo::Enumerate, SIZE> : public PiPo::EnumAttr, public PiPo::AttrArray<unsigned int, SIZE> +{ +public: + PiPoArrayAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, unsigned int initVal = NULL) : + EnumAttr(pipo, name, descr, &typeid(enum PiPo::Enumerate), changesStream), + PiPo::AttrArray<unsigned int, SIZE>() + { + for (unsigned int i = 0; i < this->size; i++) + this->value[i] = initVal; + } + + ~PiPoArrayAttr(void) { free(this->value); } + + void clone(Attr *other) { *(dynamic_cast<PiPo::AttrArray<unsigned int, SIZE> *>(this)) = *(dynamic_cast<PiPo::AttrArray<unsigned int, SIZE> *>(other)); }; + + unsigned int setSize(unsigned int size) { return this->getSize(); }; + unsigned int getSize(void) { return SIZE; } + + void set(unsigned int i, int val, bool silently = false) + { + if (i < SIZE) + (*this)[i] = (unsigned int)val; + + this->changed(silently); + }; + + void set(unsigned int i, double val, bool silently = false) + { + if (i < SIZE) + (*this)[i] = (unsigned int)val; + + this->changed(silently); + }; + + void set(unsigned int i, const char *val, bool silently = false) + { + if (i < SIZE) + (*this)[i] = getEnumIndex(val); + + this->changed(silently); + }; + + int getInt(unsigned int i) + { + if (i >= SIZE) + i = SIZE - 1; + + return (int)(*this)[i]; + }; + + double getDbl(unsigned int i) + { + if (i >= SIZE) + i = SIZE - 1; + + return (double)(*this)[i]; + }; + + const char *getStr(unsigned int i) + { + if (i < SIZE) + return this->getEnumTag(this->value[i]); + + return NULL; + }; +}; + +/*********************************************** + * + * Var Size Attribute + * + */ +template <typename TYPE> +class PiPoVarSizeAttr : public PiPo::Attr, public std::vector<TYPE> +{ +public: + PiPoVarSizeAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, unsigned int size = 0, TYPE initVal = (TYPE)0) : + Attr(pipo, name, descr, &typeid(TYPE), changesStream), + std::vector<TYPE>(size, initVal) + { + } + + void clone(Attr *other) { *(dynamic_cast<std::vector<TYPE> *>(this)) = *(dynamic_cast<std::vector<TYPE> *>(other)); }; + + unsigned int setSize(unsigned int size) { this->resize(size, (TYPE)0); return size; }; + unsigned int getSize(void) { return static_cast<unsigned int>(this->size()); } + + void set(unsigned int i, int val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = (TYPE)val; + + this->changed(silently); + }; + + void set(unsigned int i, double val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = (TYPE)val; + + this->changed(silently); + }; + + void set(unsigned int i, const char *val, bool silently = false) { }; + + int getInt(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return static_cast<int>((*this)[i]); + }; + + double getDbl(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return static_cast<double>((*this)[i]); + }; + + const char *getStr(unsigned int i) { return NULL; }; + + TYPE *getPtr() // return pointer to first data element + { + return &((*this)[0]); + }; +}; + + +template <> +class PiPoVarSizeAttr<enum PiPo::Enumerate> : public PiPo::EnumAttr, public std::vector<unsigned int> +{ +public: + PiPoVarSizeAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, unsigned int size = 0, unsigned int initVal = NULL) : + EnumAttr(pipo, name, descr, &typeid(enum PiPo::Enumerate), changesStream), + std::vector<unsigned int>(size, 0) + { + for (unsigned int i = 0; i < this->size(); i++) + (*this)[i] = initVal; + }; + + void clone(Attr *other) { *(dynamic_cast<std::vector<unsigned int> *>(this)) = *(dynamic_cast<std::vector<unsigned int> *>(other)); }; + + unsigned int setSize(unsigned int size) { this->resize(size, 0); return size; }; + unsigned int getSize(void) { return static_cast<int>(this->size()); } + + void set(unsigned int i, int val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = (unsigned int)val; + + this->changed(silently); + }; + + void set(unsigned int i, double val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = (unsigned int)val; + + this->changed(silently); + }; + + void set(unsigned int i, const char *val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = getEnumIndex(val); + + this->changed(silently); + }; + + int getInt(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return (int)(*this)[i]; + }; + + double getDbl(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return (double)(*this)[i]; + }; + + const char *getStr(unsigned int i) + { + if (i < this->size()) + return this->getEnumTag((*this)[i]); + + return NULL; + }; +}; + + +template<> +class PiPoVarSizeAttr<PiPo::Atom> : public PiPo::Attr, public std::vector<PiPo::Atom> +{ +public: + PiPoVarSizeAttr(PiPo *pipo, const char *name, const char *descr, bool changesStream, unsigned int size = 0, int initVal = 0) : + Attr(pipo, name, descr, &typeid(const char *), changesStream) + { + for (unsigned int i = 0; i < this->size(); i++) + (*this)[i] = PiPo::Atom(initVal); + }; + + void clone(Attr *other) { *(dynamic_cast<std::vector<PiPo::Atom> *>(this)) = *(dynamic_cast<std::vector<PiPo::Atom> *>(other)); }; + + unsigned int setSize(unsigned int size) { this->resize(size, PiPo::Atom(0)); return size; }; + unsigned int getSize(void) { return static_cast<unsigned int>(this->size()); } + + void set(unsigned int i, int val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = PiPo::Atom(val); + + this->changed(silently); + }; + + void set(unsigned int i, double val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = PiPo::Atom(val); + + this->changed(silently); + }; + + void set(unsigned int i, const char *val, bool silently = false) + { + if (i >= this->size()) + setSize(i + 1); + + (*this)[i] = PiPo::Atom(val); + + this->changed(silently); + }; + + int getInt(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return (*this)[i].getInt(); + }; + + double getDbl(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return (*this)[i].getDouble(); + }; + + const char *getStr(unsigned int i) + { + if (i >= this->size()) + i = static_cast<unsigned int>(this->size()) - 1; + + return (*this)[i].getString(); + }; + + PiPo::Atom *getPtr() // return pointer to first data element + { + return &((*this)[0]); + }; +}; + + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPoParallel.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPoParallel.h new file mode 100644 index 0000000000000000000000000000000000000000..97392a42a7cbfe7a8e4fd27116126e2980319000 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPoParallel.h @@ -0,0 +1,363 @@ +/** + * @file PiPoParallel.h + * @author Diemo.Schwarz@ircam.fr + * + * @brief PiPo dataflow graph class that encapsulates a parallel section of pipo modules. + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2012–2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> //db +#include <stdlib.h> //db +#include "PiPo.h" + +#define PIPO_DEBUG DEBUG*1 + +class PiPoParallel : public PiPo +{ +private: + /** class to merge several parallel pipo data streams, combining columns + */ + class PiPoMerge : public PiPo + { + private: +# define MAX_PAR 64 + int count_; + int numpar_; + PiPoStreamAttributes sa_; // combined stream attributes + int paroffset_[MAX_PAR]; // cumulative column offsets in output array + int parwidth_[MAX_PAR]; // column widths of parallel pipos + int framesize_; // output frame size = width * maxheight + + // working variables for merging of frames + PiPoValue *values_; + int time_; + unsigned int numrows_; + unsigned int numframes_; + + public: + PiPoMerge (PiPo::Parent *parent) + : PiPo(parent), count_(0), numpar_(0), sa_(1024), framesize_(0), values_(NULL) + { +#ifdef DEBUG // clean memory to make possible memory errors more consistent at least + memset(paroffset_, 0, sizeof(*paroffset_) * MAX_PAR); + memset(parwidth_, 0, sizeof(*parwidth_) * MAX_PAR); +#endif + } + + // copy constructor + PiPoMerge (const PiPoMerge &other) + : PiPo(other.parent), count_(other.count_), numpar_(other.numpar_), sa_(other.sa_), framesize_(other.framesize_) + { +#if defined(__GNUC__) && PIPO_DEBUG >= 2 + printf("\n•••••• %s: COPY CONSTRUCTOR\n", __PRETTY_FUNCTION__); //db +#endif + +#ifdef DEBUG // clean memory to make possible memory errors more consistent at least + memset(paroffset_, 0, sizeof(*paroffset_) * MAX_PAR); + memset(parwidth_, 0, sizeof(*parwidth_) * MAX_PAR); +#endif + + memcpy(paroffset_, other.paroffset_, numpar_ * sizeof(int)); + memcpy(parwidth_, other.parwidth_, numpar_ * sizeof(int)); + values_ = (PiPoValue *) malloc(sa_.maxFrames * framesize_ * sizeof(PiPoValue)); + memcpy(values_, other.values_, sa_.maxFrames * framesize_ * sizeof(PiPoValue)); + } + + // assignment operator + PiPoMerge &operator= (const PiPoMerge &other) + { +#if defined(__GNUC__) && PIPO_DEBUG >= 2 + printf("\n•••••• %s: ASSIGNMENT OPERATOR\n", __PRETTY_FUNCTION__); //db +#endif + +#ifdef DEBUG // clean memory to make possible memory errors more consistent at least + memset(paroffset_, 0, sizeof(*paroffset_) * MAX_PAR); + memset(parwidth_, 0, sizeof(*parwidth_) * MAX_PAR); +#endif + + count_ = other.count_; + numpar_ = other.numpar_; + sa_ = other.sa_; + framesize_ = other.framesize_; + + memcpy(paroffset_, other.paroffset_, numpar_ * sizeof(int)); + memcpy(parwidth_, other.parwidth_, numpar_ * sizeof(int)); + values_ = (PiPoValue *) malloc(sa_.maxFrames * framesize_ * sizeof(PiPoValue)); + memcpy(values_, other.values_, sa_.maxFrames * framesize_ * sizeof(PiPoValue)); + + return *this; + } + + // destructor + ~PiPoMerge () + { + free(values_); + } + + public: + void start (size_t numpar) + { // on start, record number of calls to expect from parallel pipos, each received stream call increments count_, when numpar_ is reached, merging has to be performed + numpar_ = (int) numpar; + count_ = 0; + } + +// TODO: signal end of parallel pipos, accomodates for possibly missing calls down the chain + void finish () + { + } + + public: + int streamAttributes (bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { // collect stream attributes declarations from parallel pipos +#if PIPO_DEBUG >= 1 + printf("PiPoParallel streamAttributes timetags %d rate %f offset %f width %d height %d labels %s varsize %d domain %f maxframes %d\n", + hasTimeTags, rate, offset, width, height, labels ? labels[0] : "n/a", hasVarSize, domain, maxFrames); +#endif + + if (count_ == 0) + { // first parallel pipo defines most stream attributes, we store then here + sa_.hasTimeTags = hasTimeTags; + sa_.rate = rate; + sa_.offset = offset; + sa_.dims[0] = width; + sa_.dims[1] = height; + sa_.numLabels = 0; + sa_.hasVarSize = hasVarSize; + sa_.domain = domain; + sa_.maxFrames = maxFrames; + sa_.concat_labels(labels, width); + + paroffset_[0] = 0; + parwidth_[0] = width; + } + else + { // apply merge rules with following pipos + // columns are concatenated + sa_.concat_labels(labels, width); + sa_.dims[0] += width; + paroffset_[count_] = paroffset_[count_ - 1] + parwidth_[count_ - 1]; + parwidth_[count_] = width; + + //TODO: check maxframes, height, should not differ + //TODO: option to transpose column vectors + } + + if (++count_ == numpar_) + { // last parallel pipo, now reserve memory and pass merged stream attributes onwards + framesize_ = sa_.dims[0] * sa_.dims[1]; + values_ = (PiPoValue *) realloc(values_, sa_.maxFrames * framesize_ * sizeof(PiPoValue)); // alloc space for maxmal block size + + return propagateStreamAttributes(sa_.hasTimeTags, sa_.rate, sa_.offset, sa_.dims[0], sa_.dims[1], sa_.labels, sa_.hasVarSize, sa_.domain, sa_.maxFrames); + } + else + return 0; // continue receiving stream attributes + } + + + int reset () + { + if (++count_ == numpar_) + return this->propagateReset(); + else + return 0; // continue receiving reset + } + + + int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { // collect data from parallel pipos + if (count_ >= numpar_) // bug is still there + { +#ifdef WIN32 + printf("%s: ARGH! count_ %d >= numpar_ %d\n", __FUNCSIG__, count_, numpar_); +#else + printf("%s: ARGH! count_ %d >= numpar_ %d\n", __PRETTY_FUNCTION__, count_, numpar_); +#endif + count_ = numpar_ - 1; + } + //assert(size / parwidth_[count_] == 1); + + int width = parwidth_[count_]; + unsigned int height = size / width; // number of input rows + + if (count_ == 0) + { // first parallel pipo determines time tag, num. rows and frames + time_ = time; + numrows_ = height; + numframes_ = num; + + // clear memory just in case one pipo doesn't output data (FIXME: handle this correctly) + memset(values_, 0, num * framesize_ * sizeof(PiPoValue)); + } + + // copy input data to be kept from parallel pipo to merged values_ + if (num > numframes_) num = numframes_; + if (height > numrows_) height = numrows_; + + for (unsigned int i = 0; i < num; i++) // for all frames present + for (unsigned int k = 0; k < height; k++) // for all rows to be kept + { + //printf("merge::frames %p\n values_ %p + %d + %d + %d,\n values %p + %d,\n size %d\n", + // this, values_, i * framesize_, k * sa_.dims[0], paroffset_[count_], values, i * size, parwidth_[count_] * sizeof(PiPoValue)); + //TODO: zero pad if num rows here: size / parwidth_[count_] < numrows_ + memcpy(values_ + i * framesize_ + k * sa_.dims[0] + paroffset_[count_], + values + i * size + k * width, width * sizeof(PiPoValue)); + } + + if (++count_ == numpar_) // last parallel pipo: pass on to receiver(s) + return propagateFrames(time_, 0 /*weight to disappear*/, values_, numrows_ * sa_.dims[0], numframes_); + else + return 0; // continue receiving frames + } + + + int finalize (double inputEnd) + { + if (count_ == 0) + time_ = inputEnd; + + if (++count_ == numpar_) + return this->propagateFinalize(time_); + else + return 0; // continue receiving finalize + } + }; // end class PiPoMerge + + PiPoMerge merge; + +public: + // constructor + PiPoParallel (PiPo::Parent *parent) + : PiPo(parent), merge(parent) + { } + + //TODO: varargs constructor PiPoParallel (PiPo::Parent *parent, PiPo *pipos ...) + +private: + // copy constructor + PiPoParallel (const PiPoParallel &other) + : PiPo(other), merge(other.merge) + { } + + // assignment operator + const PiPoParallel& operator= (const PiPoParallel &other) + { + parent = other.parent; + merge = other.merge; + + return *this; + } + +public: + // destructor + ~PiPoParallel (void) { } + + + /** @name PiPoParallel setup methods */ + /** @{ */ + + /** Add module @p{pipo} to the data flow graph in parallel. + */ + void add (PiPo *pipo) + { // add to list of receivers of this parallel module, to branch out on input + PiPo::setReceiver(pipo, true); + // then connect module to internal merge module + pipo->setReceiver(&merge); + } + + void add (PiPo &pipo) + { + add(&pipo); + } + + /** @} PiPoParallel setup methods */ + + /** @name overloaded PiPo methods */ + /** @{ */ + + void setParent (PiPo::Parent *parent) + { + this->parent = parent; + + for (unsigned int i = 0; i < receivers.size(); i++) + receivers[i]->setParent(parent); + } + + void setReceiver (PiPo *receiver, bool add = false) + { + merge.setReceiver(receiver, add); + } + + /** @name preparation and processing methods: just notify merge, and let propagate* do the branching */ + /** @{ */ + + /** start stream preparation */ + int streamAttributes (bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + merge.start(receivers.size()); + return PiPo::propagateStreamAttributes(hasTimeTags, rate, offset, width, height, labels, hasVarSize, domain, maxFrames); + } + + int reset () + { + merge.start(receivers.size()); + return PiPo::propagateReset(); + } + + /** @} end of preparation of processing methods */ + + /** @name processing */ + /** @{ */ + + int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { + merge.start(receivers.size()); + return PiPo::propagateFrames(time, weight, values, size, num); + } + + int finalize (double inputEnd) + { + merge.start(receivers.size()); + return PiPo::propagateFinalize(inputEnd); + } + + /** @} end of processing methods */ + /** @} end of overloaded PiPo methods */ +}; + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPoSequence.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPoSequence.h new file mode 100644 index 0000000000000000000000000000000000000000..c92dd88d8a29ceb7c23acc6a192afdc81e4c90bf --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/PiPoSequence.h @@ -0,0 +1,263 @@ +/** + * @file PiPoSequence.h + * @author Diemo.Schwarz@ircam.fr + * + * @brief PiPo dataflow graph class that encapsulates a sequence of pipo modules. + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2012–2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_SEQUENCE_ +#define _PIPO_SEQUENCE_ + +#include "PiPo.h" + +class PiPoSequence : public PiPo +{ +private: + std::vector<PiPo *> seq_; + +public: + // constructor + PiPoSequence (PiPo::Parent *parent) + : PiPo(parent), seq_() + { } + +#if __cplusplus > 199711L // check for C++11 + /** varargs constructor with a list of pipos that will be connected: + + PiPoSequence (PiPo::Parent *parent, PiPo &pipos ...) + seq(parent, pipo1, pipo2, ...); + + (using C++11 variadic templates) + */ + template<typename ...Args> + PiPoSequence (PiPo::Parent *parent, Args&... pipos) + : PiPo(parent), seq_{&pipos ...} // use C++11 initilizer_list syntax and variadic templates + { + // set parents of all pipos? + connect(NULL); + } +#endif + + // copy constructor + PiPoSequence (const PiPoSequence &other) + : PiPo(other), seq_(other.seq_) + { + connect(NULL); + } + + // assignment operator + const PiPoSequence& operator=(const PiPoSequence &other) + { + parent = other.parent; + seq_ = other.seq_; + connect(NULL); + + return *this; + } + + ~PiPoSequence (void) { } + + + /** @name PiPoSequence setup methods */ + /** @{ */ + + /** append module \p pipo to sequential data flow graph + */ + void add (PiPo *pipo, bool autoconnect = true) + { + seq_.push_back(pipo); + + if (autoconnect && seq_.size() > 1) + seq_[seq_.size() - 2]->setReceiver(pipo); // connect previous to just added pipo + } + + void add (PiPo &pipo, bool autoconnect = true) + { + add(&pipo, autoconnect); + } + + + void clear () + { + for (unsigned int i = 0; i < seq_.size(); i++) + seq_[i] = NULL; + + seq_.clear(); + } + + + /** connect each PiPo in PiPoSequence (from end to start) + + @param receiver is terminating PiPo of the host that finally receives data + */ + bool connect (PiPo *receiver) + { + PiPo *next = getTail(); + + if (next != NULL) + { + next->setReceiver(receiver); + + for (int i = static_cast<int>(seq_.size()) - 2; i >= 0; i--) + { + PiPo *pipo = seq_[i]; + pipo->setReceiver(next); + next = pipo; + } + + return true; + } + + return false; + } + + /** @} PiPoSequence setup methods */ + + /** @name PiPoChain query methods */ + /** @{ */ + + int getSize() const + { + return static_cast<int>(seq_.size()); + } + + PiPo *getHead () const + { + if (seq_.size() > 0) + return seq_[0]; + + return NULL; + } + + PiPo *getTail () const + { + if (seq_.size() > 0) + return seq_[seq_.size() - 1]; + + return NULL; + } + + PiPo *getPiPo (unsigned int index) const + { + //printf("%s(%d) -> %p\n", __PRETTY_FUNCTION__, index, seq_[index]); + + if (index < seq_.size()) + return seq_[index]; + + return NULL; + } + + /** @} PiPoSequence query methods */ + + /** @name overloaded PiPo methods */ + /** @{ */ + + void setParent (PiPo::Parent *parent) + { + this->parent = parent; + + for (unsigned int i = 0; i < seq_.size(); i++) + seq_[i]->setParent(parent); + } + + void setReceiver (PiPo *receiver, bool add = false) + { + PiPo *tail = getTail(); + + if (tail != NULL) + tail->setReceiver(receiver, add); + } + + /** @name preparation of processing */ + /** @{ */ + + /** start stream preparation */ + int streamAttributes (bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + PiPo *head = getHead(); + + if (head != NULL) + return head->streamAttributes(hasTimeTags, rate, offset, width, height, labels, hasVarSize, domain, maxFrames); + + return -1; + } + + int reset () + { + PiPo *head = getHead(); + + if (head != NULL) + return head->reset(); + + return -1; + } + + /** @} end of preparation of processing methods */ + + /** @name processing */ + /** @{ */ + + int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { + PiPo *head = getHead(); + + if (head != NULL) + return head->frames(time, weight, values, size, num); + + return -1; + } + + int finalize (double inputEnd) + { + PiPo *head = getHead(); + + if (head != NULL) + return head->finalize(inputEnd); + + return -1; + } + + /** @} end of processing methods */ + /** @} end of overloaded PiPo methods */ +}; + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif /* _PIPO_SEQUENCE_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/RingBuffer.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/RingBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..f5e38f952db243ba044c60616bb17cc1746ce108 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/RingBuffer.h @@ -0,0 +1,121 @@ +/** + * @file RingBuffer.h + * @author Norbert Schnell + * @author Diemo Schwarz + * + * @brief ringbuffer class + * + * @ingroup pipoapi + * + * @copyright + * Copyright (C) 2012–2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of mosquitto nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RINGBUFFER_ +#define _RINGBUFFER_ + +template <class T> +class RingBuffer +{ +public: + std::vector<T> vector; + unsigned int width; + unsigned int size; + unsigned int index; + bool filled; + +public: + RingBuffer (void) + : vector() + { + this->width = 1; + this->size = 0; + this->index = 0; + this->filled = false; + }; + + void resize (int width, int size) + { + this->vector.resize(width * size); + this->width = width; + this->size = size; + this->index = 0; + this->filled = false; + }; + + void reset (void) + { + this->index = 0; + this->filled = false; + }; + + int input (T *values, unsigned int num, PiPoValue scale = 1.0) + { + T *ringValues = &this->vector[this->index * this->width]; + + if (num > this->width) + num = this->width; + + /* copy frame */ + if (scale == 1.0) /*TODO: some polymorphism and template magic to avoid this if clause */ + memcpy(ringValues, values, num * sizeof(T)); + else + { + for (unsigned int j = 0; j < num; j++) + ringValues[j] = values[j] * scale; + } + + /* zero pad this values */ + if (num < this->width) + memset(ringValues + num, 0, (this->width - num) * sizeof(T)); + + this->index++; + + if (this->index >= this->size) + { + filled = true; + this->index = 0; + } + + if (this->filled) + return this->size; + else + return this->index; + }; +}; + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif /* _RINGBUFFER_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/mimo.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/mimo.h new file mode 100644 index 0000000000000000000000000000000000000000..ef7020d80b2d13a1aa25370f3db5fdfd821b43e3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/include/mimo.h @@ -0,0 +1,144 @@ + +#ifndef _MIMO_H_INCLUDED_ +#define _MIMO_H_INCLUDED_ + +#include "PiPo.h" +#include <memory> + +/* interface for a class that holds the mimo module-specific model parameters resulting from training + */ +class mimo_model_data +{ +public: + /** output as json string into out + Throws an exception if string would exceed size. + + @param out string buffer of length \p{size} + @param size size of string buffer + @return returns the out pointer for convenience + + N.B.: the mimo module might be loaded from a dynamic library, so + we can't return a complex object such as std::string that + internatlly uses heap allocations, since the dylib's heap is a + separate one from the main app */ + virtual char *to_json (char *out, int size) throw() = 0; + + /** get model from json string */ + virtual int from_json (const char *json_string) = 0; + + // virtual const int foo() = 0; +}; + +/* + + every mimo module inherits the basic stream description and data + passing methods (streamAttributes() and frames()) from PiPo, but + ignores real-time oriented methods (segment()), and adds iteration + for training. + */ + +class Mimo : public PiPo +{ +public: + // constructor + Mimo (PiPo::Parent *parent, Mimo *receiver = NULL) + : PiPo(parent, receiver) + { + }; + + Mimo (const Mimo &other) + : PiPo(other) + { + } + + /** the PiPo::frames() method performs decoding */ + //virtual int frames (...); + + /** prepare for training + + @param numbuffers number of buffers with training data + @param numtracks number of tracks per input buffer with training data + @param bufsizes array[numbuffers] of numbers of frames for each input buffer + @param streamattr array[numtracks] attributes of input data for each input track + @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + virtual int setup (int numbuffers, int numtracks, int bufsizes[], const PiPoStreamAttributes *streamattr[]) = 0; + + /** the train method performs one iteration of training. + It is called for each buffer and each input track, receiving the training data sets. + The first iteration receives the original data, further iterations the training output data of previous iterations, + that each iteration can output by calling propagateTrain(). + For multi-modal training (with more than one input track), only the call for the last track may call propagateTrain(). + + @param itercount number of current iteration (starts at zero) + @param bufferindex index of current input buffer (up to numbuffers - 1) + @param trackindex index of current input track (up to numtracks - 1) + @param numframes number of frames in @p{data} + @param data input data in format given by @p{streamattr} + @param timetags pointer to @p{numframes} time tags or NULL when sampled + @param varsize pointer to @p{numframes} of row sizes or NULL when constant size + @return status flag: continue training (> 0), stop training (== 0), error (< 0) + + N.B.: we could replace the constraints on calling sequence by a more complicated input format where pointers to data and attributes of each input track are passed as arrays, that would penalise the vast majority of single-track use cases: + + virtual int train (int itercount, int bufferindex, int numframes[], PiPoValue *data[], double *timetags[], int *varsize[]) = 0; + */ + virtual int train (int itercount, int bufferindex, int trackindex, int numframes, const PiPoValue *data, const double *timetags, const int *varsize) = 0; + + virtual int train (int itercount, int bufferindex, int trackindex, int numframes, const PiPoValue *data, const double starttime, const int *varsize) + { + return train (itercount, bufferindex, trackindex, numframes, data, (const double *) NULL, varsize); + } + + + /** return recommended max number of iterations, or 0 for no limit. + This can be overridden by the user via an attribute + N.B.: The host should ask for maxiter at every iteration, so that a training algorithm can adapt its recommendation to the training progress */ + virtual int maxiter() { return 0; /* unlimited */ } + + /** return error, distance or loss metric from training */ + virtual double getmetric() { return 0; /* whatever */ }; + + /** return trained model parameters */ + virtual mimo_model_data *getmodel () = 0; + + int propagateSetup (int numbuffers, int numtracks, int bufsize[], const PiPoStreamAttributes *streamattr[]) + { + int ret = 0; + + for(unsigned int i = 0; i < this->receivers.size(); i++) + { + ret = dynamic_cast<Mimo *>(this->receivers[i])->setup(numbuffers, 1, bufsize, &streamattr[0]); + + if(ret < 0) + break; + } + + return ret; + } + + int propagateTrain(int itercount, int bufferindex, int trackindex, int numframes, const PiPoValue *data, const double *timetags, const int *varsize) + { + int ret = 0; + + for (unsigned int i = 0; i < this->receivers.size(); i++) + { + ret = dynamic_cast<Mimo *>(this->receivers[i])->train(itercount, bufferindex, trackindex, numframes, data, timetags, varsize); + + if(ret < 0) + break; + } + + return ret; + } +}; + + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif // defined _MIMO_H_INCLUDED_ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBands.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBands.h new file mode 100644 index 0000000000000000000000000000000000000000..f3678673494e13c730ecb8ddd2f8d9fe4a1d7aa2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBands.h @@ -0,0 +1,356 @@ +/** + * @file PiPoBands.h + * @author Norbert.Schnell@ircam.fr + * + * @brief RTA bands PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_BANDS_ +#define _PIPO_BANDS_ + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_complex.h" +#include "rta_bands.h" +#include "rta_mel.h" +#include <float.h> +#include <math.h> +} + +#include <vector> +//#include <complex> + +#ifdef WIN32 +static float cabsf(floatcomplex value) +{ + _complex cval = { value.real, value.imag }; + return (float)_cabs(cval); +} +#endif + +class PiPoBands : public PiPo +{ +public: + enum BandsModeE { UndefinedBands = -1, MelBands = 0, HtkMelBands = 1 }; //todo: bark, erb + enum EqualLoudnessModeE { None = 0, Hynek = 1 }; + +private: + std::vector<float> bands; + std::vector<float> weights; + std::vector<unsigned int> bounds; + std::vector<float> bandfreq; // band centre frequency in Hz + std::vector<float> eqlcurve; // equal loudness curve + std::vector<float> power_spectrum; + + enum BandsModeE bandsMode; + enum EqualLoudnessModeE eqlMode; + unsigned int specSize; + bool complex_input; + float sampleRate; + +public: + /** + * @var mode + * "mel" (MEL bands, normalized energy) + * or "htkmel" (HTK-like MEL bands, preserved peak energy) + */ + PiPoScalarAttr<PiPo::Enumerate> mode; + + /** + * @var eqlmode + * "none" (no scaling) + * or "hynek" (Hynek's equal loudness curve) + */ + PiPoScalarAttr<PiPo::Enumerate> eqlmode; + + /** + * @var num + * number of bands + */ + PiPoScalarAttr<int> num; + + /** + * @var log + * enable logarithmic bands + */ + PiPoScalarAttr<bool> log; + + /** + * @var power + * power scaling exponent + */ + PiPoScalarAttr<float> power; + + PiPoBands(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + bands(), weights(), bounds(), bandfreq(), + mode(this, "mode", "Bands Mode", true, MelBands), + eqlmode(this, "eqlmode", "Equal Loudness Curve", true, None), + num(this, "num", "Number Of Bands", true, 24), + log(this, "log", "Logarithmic Bands", false, true), + power(this, "power", "Power Scaling Exponent", false, 1.) + { + this->bandsMode = UndefinedBands; + this->eqlMode = None; + + this->specSize = 0; + this->complex_input = false; + this->sampleRate = 1.0; + + this->mode.addEnumItem("mel", "MEL bands (normalized band energy)"); + this->mode.addEnumItem("htkmel", "HTK like MEL bands (preserved peak energy)"); + + this->eqlmode.addEnumItem("none", "no equal loudness scaling"); + this->eqlmode.addEnumItem("hynek", "Hynek's equal loudness curve"); + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + enum BandsModeE bandsMode = (enum BandsModeE)this->mode.get(); + enum EqualLoudnessModeE eqlMode = (enum EqualLoudnessModeE)this->eqlmode.get(); + int numBands = this->num.get(); + int specSize = size; + float sampleRate = 2.0 * domain; + + if (width >= 2) + { + complex_input = true; + power_spectrum.resize(specSize); + } + + if(bandsMode < MelBands) + bandsMode = MelBands; + else if(bandsMode > HtkMelBands) + bandsMode = HtkMelBands; + + if(numBands < 1) + numBands = 1; + + if(specSize < 0) + specSize = 0; + + if(bandsMode != this->bandsMode || eqlMode != this->eqlMode || numBands != this->bands.size() || specSize != this->specSize || sampleRate != this->sampleRate) + { + this->bands.resize(numBands); + this->eqlcurve.resize(numBands); + this->weights.resize(specSize * numBands); + this->bounds.resize(2 * numBands); + this->bandfreq.resize(numBands); + + this->bandsMode = bandsMode; + this->eqlMode = eqlMode; + this->specSize = specSize; + this->sampleRate = sampleRate; + + switch(bandsMode) + { + default: + case MelBands: + { + rta_spectrum_to_mel_bands_weights(&this->weights[0], &this->bounds[0], specSize, + sampleRate, numBands, 0.0, domain, 1.0, + rta_hz_to_mel_slaney, rta_mel_to_hz_slaney, rta_mel_slaney); + + // calculate band centre freqs (TODO: pass up from rta_spectrum_to_mel_bands_weights) + for (int i = 0; i < numBands; i++) + { + double b = (bounds[2 * i] + bounds[2 * i + 1]) / 2.; // take mean as band centre freq + bandfreq[i] = b / (double) specSize * sampleRate / 2. ; // in Hz + } + break; + } + + case HtkMelBands: + { + rta_spectrum_to_mel_bands_weights(&this->weights[0], &this->bounds[0], specSize, + sampleRate, numBands, 0.0, domain, 1.0, + rta_hz_to_mel_htk, rta_mel_to_hz_htk, rta_mel_htk); + + // calculate band centre freqs (TODO: pass up from rta_spectrum_to_mel_bands_weights) + for (int i = 0; i < numBands; i++) + { + double b = (bounds[2 * i] + bounds[2 * i + 1]) / 2.; // take mean as band centre freq + bandfreq[i] = b / (double) specSize * sampleRate / 2. ; // in Hz + } + break; + } + /* + case ERBBands: + rta_spectrum_to_erb_bands_weights(&weights[0], &bounds[0], &bandfreq[0], specSize, + sampleRate, numBands); + break; + */ + } + + switch (this->eqlmode.get()) + { + case Hynek: + + for (int i = 0; i < numBands; i++) + { // Hynek's equal-loudness-curve formula + double fsq = bandfreq[i] * bandfreq[i]; + double ftmp = fsq / (fsq + 1.6e5); + eqlcurve[i] = (ftmp * ftmp) * ((fsq + 1.44e6) / (fsq + 9.61e6)); + } + break; + + default: /* curve will not be applied */ + break; + } + } + +#if (DEBUG * 0) + printf("PiPoBands::streamAttributes timetags %d rate %.0f offset %f width %d size %d " + "labels %s varsize %d domain %f maxframes %d\nrta_real_t size = %d\n", + hasTimeTags, rate, offset, (int) width, (int) size, labels ? labels[0] : "n/a", + (int) hasVarSize, domain, (int) maxFrames, sizeof(rta_real_t)); + static FILE *filtout = fopen("/tmp/melfilter.raw", "w"); + fwrite(&weights[0], weights.size(), sizeof(float), filtout); + static FILE *bout = fopen("/tmp/melbounds.raw", "w"); + fwrite(&bounds[0], bounds.size(), sizeof(int), bout); +#endif + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, numBands, 1, NULL, 0, 0.0, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + unsigned int numBands = static_cast<int>(this->bands.size()); + bool log = this->log.get(); + float p = this->power.get(); + float *spectrum; + int specsize = size; + + for(unsigned int i = 0; i < num; i++) + { + float scale = 1.0; + + switch(this->bandsMode) + { + default: + case MelBands: + { + scale *= 66519.0 / numBands; + break; + } + case HtkMelBands: + { + break; + } + } + + if (complex_input) + { // convert to power spectrum + specsize = static_cast<int>(power_spectrum.size()); + spectrum = &(power_spectrum[0]); + + for (int i = 0; i < specsize; i++) + spectrum[i] = cabsf(((rta_complex_t *) values)[i]); + +#if (DEBUG * 0) + static FILE *specout = fopen("/tmp/powerspectrum.raw", "w"); + fwrite(spectrum, sizeof(float), specsize, specout); +#endif + } + else + spectrum = values; + + /* calculate MEL bands */ + rta_spectrum_to_bands_abs(&this->bands[0], spectrum, + &this->weights[0], &this->bounds[0], + specsize, numBands); + + /* apply equal loudness curve*/ + if (this->eqlmode.get() != None) + { + for (unsigned int j = 0; j < numBands; j++) + this->bands[j] *= this->eqlcurve[j]; + } + + if(log) + scale *= numBands; + + if(scale != 1.0) + { + for(unsigned int j = 0; j < numBands; j++) + this->bands[j] *= scale; + } + + if(log) + { + const double minLogValue = 1e-48; + const double minLog = -480.0; + + /* calculate log output values */ + for(unsigned int i = 0; i < numBands; i++) + { + float band = this->bands[i]; + + if(band > minLogValue) + this->bands[i] = 10.0 * log10f(band); + else + this->bands[i] = minLog; + } + } + + if (p != 1) + { + for (unsigned int j = 0; j < numBands; j++) + this->bands[j] = powf(this->bands[j], p); + } + + int ret = this->propagateFrames(time, weight, &this->bands[0], numBands, 1); + + if(ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + +/** EMACS ** + * Local variables: + * mode: c++ + * c-file-style: "stroustrup" + * c-basic-offset:2 + * End: + */ + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBayesFilter.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBayesFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..57e456ae9d7a1f74feea2fd4810beea4e0f1dcdd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBayesFilter.h @@ -0,0 +1,149 @@ +/** + * @file PiPoBayesFilter.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo implementing the Bayesian Filtering of myoelectric signals algorithm + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_BAYESFILTER_ +#define _PIPO_BAYESFILTER_ + +#include "BayesianFilter.h" +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_mean_variance.h" +} + +#include <vector> +using namespace std; + +#define RING_ALLOC_BLOCK 256 + +class PiPoBayesFilter : public PiPo { + BayesianFilter filter; + vector<float> observation; + vector<float> output; + + public: + PiPoScalarAttr<float> logdiffusion; + PiPoScalarAttr<float> logjumprate; + PiPoVarSizeAttr<float> mvc; + + // ------------------------------------ + // -- Deprecated Attributes + PiPoScalarAttr<float> clipping; + PiPoScalarAttr<float> alpha; + PiPoScalarAttr<float> beta; + PiPoScalarAttr<bool> rectification; + // ------------------------------------ + + PiPoBayesFilter(PiPo::Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + logdiffusion(this, "logdiffusion", "log diffusion rate", true, -2.), + logjumprate(this, "logjumprate", "log probability of sudden jumps", + true, -5.), + mvc(this, "mvc", "Maximum Value Contraction", true, 1.), + // ------------------------------------ + // -- Deprecated Attributes + clipping(this, "clipping", "clipping [DEPRECATED]", true, 1.), + alpha(this, "alpha", "alpha [DEPRECATED]", true, 0.01), + beta(this, "beta", "beta [DEPRECATED]", true, 0.01), + rectification(this, "rectification", + "signal rectification [DEPRECATED]", true, true) { + // ------------------------------------ + this->filter.diffusion = powf(10., this->logdiffusion.get()); + this->filter.jump_rate = powf(10., this->logjumprate.get()); + this->mvc.setSize(1); + this->mvc.set(0, 1.); + this->filter.mvc[0] = this->mvc.getDbl(0); + this->filter.init(); + }; + + ~PiPoBayesFilter(void){}; + + int streamAttributes(bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int size, + const char **labels, bool hasVarSize, double domain, + unsigned int maxFrames) { + this->mvc.resize(width, 1.); + this->filter.resize(width); + this->filter.samplerate = rate; + this->filter.diffusion = powf(10., this->logdiffusion.get()); + this->filter.jump_rate = powf(10., this->logjumprate.get()); + for (unsigned int i = 0; i < width; i++) { + this->filter.mvc[i] = this->mvc.getDbl(i); + } + this->filter.init(); + + this->output.resize(width * size * maxFrames); + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, width, + size, labels, 0, 0.0, 1); + }; + + int reset(void) { + this->filter.init(); + return this->propagateReset(); + }; + + int frames(double time, double weight, float *values, unsigned int size, + unsigned int num) { + float *output = &(this->output[0]); + + for (unsigned int i = 0; i < num; i++) { + this->observation.resize(size); + for (unsigned int j = 0; j < size; j++) + this->observation[j] = double(values[j]); + + this->filter.update(observation); + + for (unsigned int j = 0; j < size; j++) + output[j] = float(this->filter.output[j]); + + int ret = this->propagateFrames(time, weight, output, size, 1); + + if (ret != 0) return ret; + + values += size; + output += size; + } + + return 0; + }; +}; + +#endif /* _PIPO_BAYESFILTER_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBiquad.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBiquad.h new file mode 100644 index 0000000000000000000000000000000000000000..38f1ae0a85b8e55b5514648dd9e52cb036a2a795 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoBiquad.h @@ -0,0 +1,306 @@ +/** + * @file PiPoBiquad.h + * @author Joseph Larralde + * @date 30.11.2015 + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2015 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_BIQUAD_H_ +#define _PIPO_BIQUAD_H_ + +#define PIPO_BIQUAD_MIN_Q 0.001 + +#ifdef WIN32 +#define M_SQRT1_2 0.70710678118654752440084436210 +#endif + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_biquad.h" +} + +#include <math.h> +#include <stdlib.h> + +class PiPoBiquad : public PiPo +{ +public: + enum BiquadTypeE { DF1BiquadType = 0, DF2TBiquadType = 1}; + enum FilteringModeE { LowPassFilteringMode = 0, HighPassFilteringMode = 1, ResonantFilteringMode = 2, BandPassFilteringMode = 3, BandStopFilteringMode = 4, AllPassFilteringMode = 5, PeakNotchFilteringMode = 6, LowShelfFilteringMode = 7, HighShelfFilteringMode = 8, RawCoefsFilteringMode = 9}; + enum FrameRateUnitE { FrameUnit = 0, HertzUnit = 1 }; + +private: + BiquadTypeE biquadType;; + FilteringModeE filterMode; + //FrameRateUnitE unit; + + + unsigned int frameWidth; + unsigned int frameHeight; + + float frameRate; + float *outValues; + + float b[3]; /* biquad feed-forward coefficients b0, b1 and b2*/ + float a[2]; /* biquad feed-backward coefficients a1 and a2 */ + float *biquadState; + unsigned int biquadState_nb; /* number of state: 4 for df1 and 2 for df2t */ + + double f0; + double normF0; + + float biquadGain; + float biquadQuality; + float biquadQNormalisation; + +public: + PiPoScalarAttr<float> b0; + PiPoScalarAttr<float> b1; + PiPoScalarAttr<float> b2; + //PiPoScalarAttr<float> a0; // -> a0 is always 1 + PiPoScalarAttr<float> a1; + PiPoScalarAttr<float> a2; + PiPoScalarAttr<PiPo::Enumerate> biquadTypeA; + PiPoScalarAttr<PiPo::Enumerate> filterModeA; + //PiPoScalarAttr<PiPo::Enumerate> unitA; + PiPoScalarAttr<float> gainA; + PiPoScalarAttr<float> frequencyA; + PiPoScalarAttr<float> QA; + + //=================== CONSTRUCTOR ====================// + + PiPoBiquad(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + b0(this, "b0", "b0 biquad coefficient", true, 1.), + b1(this, "b1", "b1 biquad coefficient", true, 0.), + b2(this, "b2", "b2 biquad coefficient", true, 0.), + a1(this, "a1", "a1 biquad coefficient", true, 0.), + a2(this, "a2", "a2 biquad coefficient", true, 0.), + biquadTypeA(this, "biquadtype", "Direct Form 1 or 2T", true, DF1BiquadType), + filterModeA(this, "filtermode", "Filter Mode", true, LowPassFilteringMode), + //unitA(this, "unit", "Framerate Unit", true, FrameUnit), + gainA(this, "gain", "Filter Gain", true, 1.), + frequencyA(this, "frequency", "Filter Relevant Frequency", true, 1000.), + QA(this, "Q", "Filter Quality", true, 0.) + { + + + this->frameWidth = 0; + this->frameHeight = 0; + + this->frameRate = 1.; + this->outValues = NULL; + + this->biquadType = DF1BiquadType; + this->biquadState_nb = 4; + this->biquadGain = 1.; + this->biquadQuality = 0.; + this->biquadQNormalisation = M_SQRT1_2; + + this->filterMode = LowPassFilteringMode; + + this->b[0] = 1.; + this->b[1] = 0.; + this->b[2] = 0.; + this->a[0] = 0.; + this->a[1] = 0.; + this->biquadState = NULL; + + this->biquadTypeA.addEnumItem("DF1", "Direct Form 1"); + this->biquadTypeA.addEnumItem("DF2", "Direct Form 2"); + + this->filterModeA.addEnumItem("lowpass", "Lowpass Filtering Mode"); + this->filterModeA.addEnumItem("highpass", "Highpass Filtering Mode"); + this->filterModeA.addEnumItem("resonant", "Resonant Filtering Mode"); + this->filterModeA.addEnumItem("bandpass", "Bandpass Filtering Mode"); + this->filterModeA.addEnumItem("bandstop", "Bandstop Filtering Mode"); + this->filterModeA.addEnumItem("allpass", "Allpass Filtering Mode"); + this->filterModeA.addEnumItem("peaknotch", "Peaknotch Filtering Mode"); + this->filterModeA.addEnumItem("lowshelf", "Lowshelf Filtering Mode"); + this->filterModeA.addEnumItem("highshelf", "Highshelf Filtering Mode"); + this->filterModeA.addEnumItem("rawcoefs", "Controlled By Raw Coefficients"); + + //this->unitA.addEnumItem("frame", "Raw Frames"); + //this->unitA.addEnumItem("Hz", "Framerate Expressed in Hertz"); + } + + ~PiPoBiquad() + { + free(this->biquadState); + free(this->outValues); + } + + void initBiquadCoefficients() + { + float q = this->biquadQuality; + + if(this->biquadQNormalisation != 1.) { + q *= this->biquadQNormalisation; + } + + rta_biquad_coefs(b, a, (rta_filter_t)filterMode, normF0, q, biquadGain); + } + + void filterFrame(float *frameValues, float *outValues)//, int nFrames) + { + switch(this->biquadType) { + case DF1BiquadType: + for(unsigned int i = 0; i < this->frameHeight; i++) { + for(unsigned int j = 0; j < this->frameWidth; j++) { + outValues[i * this->frameWidth + j] = rta_biquad_df1_stride(frameValues[i * this->frameWidth + j], b, 1, a, 1, &(this->biquadState[j]), this->frameWidth); + } + } + break; + + case DF2TBiquadType: + for(unsigned int i = 0; i < this->frameHeight; i++) { + for(unsigned int j = 0; j < this->frameWidth; j++) { + outValues[i * this->frameWidth + j] = rta_biquad_df2t_stride(frameValues[i * this->frameWidth + j], b, 1, a, 1, &(this->biquadState[j]), this->frameWidth); + } + } + break; + } + } + // additionnal buffer for filter memory ? -> no ! (taken care of by biquadState array) + + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + enum BiquadTypeE biquadType = (enum BiquadTypeE)this->biquadTypeA.get(); + enum FilteringModeE filterMode = (enum FilteringModeE)this->filterModeA.get(); + //enum FrameRateUnitE unit = (enum FrameRateUnitE)this->unitA.get(); + + float gain = this->gainA.get(); + float frequency = this->frequencyA.get(); + float Q = this->QA.get(); + + unsigned int frameWidth = width; + unsigned int frameHeight = size; + + + if(frameWidth != this->frameWidth || frameHeight != this->frameHeight) + { + this->frameWidth = frameWidth; + this->frameHeight = frameHeight; + + this->biquadState = (float *)realloc(this->biquadState, 4 * this->frameWidth * sizeof(float)); + memset(this->biquadState, 0., 4 * this->frameWidth); + this->outValues = (float *)realloc(this->outValues, this->frameWidth * this->frameHeight * sizeof(float)); + } + + if(biquadType != this->biquadType) + { + this->biquadType = biquadType; + if(this->biquadType == DF1BiquadType) { + this->biquadState_nb = 4; + } else { // this->biquadType == DF2TBiquadType + this->biquadState_nb = 2; + } + } + + if(this->filterMode == RawCoefsFilteringMode) + { + float a1 = this->a1.get(); + float a2 = this->a2.get(); + float b0 = this->b0.get(); + float b1 = this->b1.get(); + float b2 = this->b2.get(); + + if(a1 != this->a[0] || a2 != this->a[1] || b0 != this->b[0] || b1 != this->b[1] || b2 != this->b[2]) + { + a[0] = a1; + a[1] = a2; + b[0] = b0; + b[1] = b1; + b[2] = b2; + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, width, size, labels, 0, 0.0, 1); + } + + // if not in raw coefs control mode, compute coefs from gain / frequency / quality : + + if(filterMode != this->filterMode || rate != this->frameRate) + { + this->filterMode = filterMode; + this->frameRate = rate; + initBiquadCoefficients(); + } + + //============================ more likely to change ============================// + if(gain != this->biquadGain || frequency != this->f0 || Q != this->biquadQuality) + { + this->biquadQuality = fmax(fmin(Q, 1.), PIPO_BIQUAD_MIN_Q); + this->QA.set(this->biquadQuality, true); + + this->f0 = fmax(fmin(frequency, this->frameRate), 0.); + this->frequencyA.set(this->f0, true); + this->normF0 = this->f0 / this->frameRate; + + this->biquadGain = fmax(gain, 0.); + this->gainA.set(this->biquadGain, true); + + initBiquadCoefficients(); + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, width, size, labels, false, 0.0, 1); + } + + int reset() + { + memset(this->biquadState, 0., 4 * this->frameWidth); + return this->propagateReset(); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + double outputTime = time; + for(unsigned int i = 0; i < num; i++) + { + //outputTime += (1000. / this->frameRate); + filterFrame(values, this->outValues); + int ret = this->propagateFrames(outputTime, weight, this->outValues, this->frameWidth * this->frameHeight, 1); + if(ret != 0) + return ret; + + values += size; + } + return 0; + } + +}; + +#endif /* _PIPO_BIQUAD_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoChop.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoChop.h new file mode 100644 index 0000000000000000000000000000000000000000..bd39aab8d690396a1be0de0ea5f7e2953aff1db5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoChop.h @@ -0,0 +1,246 @@ +/** + * @file PiPoChop.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo equidistant segmentation and temporal modeling + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_CHOP_ +#define _PIPO_CHOP_ + +#include "PiPo.h" +#include "TempMod.h" +#include <vector> +#include <string> + +extern "C" { +#include <float.h> +} + +// keep quiet! +#undef DEBUG + + +class PiPoChop : public PiPo +{ +public: + PiPoScalarAttr<double> offset_; + PiPoScalarAttr<double> chopsize_; + PiPoScalarAttr<bool> enDuration_; + PiPoScalarAttr<bool> enMin_; + PiPoScalarAttr<bool> enMax_; + PiPoScalarAttr<bool> enMean_; + PiPoScalarAttr<bool> enStddev_; + +private: + double nexttime_; + int report_duration_; // caches enDuration_ as index offset, mustn't change while running + TempModArray tempmod_; + std::vector<PiPoValue> outputvalues_; + + // return next chop time or infinity when not chopping + double getnexttime () + { + return chopsize_.get() > 0 ? offset_.get() + chopsize_.get() : DBL_MAX; + } + +public: + PiPoChop (Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + tempmod_(), + offset_ (this, "offset", "Time Offset Before Starting Segmentation [ms]", false, 0), + chopsize_(this, "size", "Chop Size [ms] (0 = chop at end)", false, 242), + enDuration_(this, "duration", "Output Segment Duration", true, false), + enMin_ (this, "min", "Calculate Segment Min", true, false), + enMax_ (this, "max", "Calculate Segment Max", true, false), + enMean_ (this, "mean", "Calculate Segment Mean", true, true), // at least one tempmod on + enStddev_(this, "stddev", "Calculate Segment StdDev", true, false) + { + nexttime_ = getnexttime(); + report_duration_ = 0; + } + + ~PiPoChop (void) + { + } + + int streamAttributes (bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int size, + const char **labels, bool hasVarSize, double domain, + unsigned int maxFrames) + { +#ifdef DEBUG + printf("PiPoChop streamAttributes timetags %d rate %.0f offset %f width %d size %d labels %s " + "varsize %d domain %f maxframes %d\n", + hasTimeTags, rate, offset, (int) width, (int) size, labels ? labels[0] : "n/a", (int) hasVarSize, domain, (int) maxFrames); +#endif + + nexttime_ = getnexttime(); + report_duration_ = (int) enDuration_.get(); + + /* resize temporal models */ + tempmod_.resize(width); + + /* enable temporal models */ //TODO: switch at least one on + tempmod_.enable(enMin_.get(), enMax_.get(), enMean_.get(), enStddev_.get()); + + /* get output size */ + unsigned int outputsize = tempmod_.getNumValues(); + + /* alloc output vector for duration and temporal modelling output */ + outputvalues_.resize(outputsize + report_duration_); + + /* get labels */ + char *mem = new char[(outputsize + report_duration_) * 64]; + char **outlabels = new char*[outputsize + report_duration_]; + + for (unsigned int i = 0; i < outputsize + report_duration_; i++) + outlabels[i] = mem + i * 64; + + if (report_duration_) + snprintf(outlabels[0], 64, "Duration"); + tempmod_.getLabels(labels, width, &outlabels[report_duration_], 64, outputsize); + + int ret = this->propagateStreamAttributes(true, rate, 0.0, outputsize + report_duration_, 1, (const char **) &outlabels[0], false, 0.0, 1); + + delete [] mem; + delete [] outlabels; + + return ret; + } + + int reset (void) + { + nexttime_ = getnexttime(); + tempmod_.reset(); + + return this->propagateReset(); + }; + + + int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { +#ifdef DEBUG + //printf("PiPoChop frames time %f (next %f) size %d num %d\n", time, nexttime_, size, num); +#endif + + int ret = 0; + + if (time >= offset_.get()) + { + // at first crossing of offset, nexttime_ == offset + duration + + if (time >= nexttime_) + { + int outsize = static_cast<int>(outputvalues_.size()); + + if (report_duration_) + //TBD: calculate actual duration quantised to frame hops? + outputvalues_[0] = chopsize_.get(); + + /* get temporal modelling */ + tempmod_.getValues(&outputvalues_[report_duration_], outsize - report_duration_, true); + +#ifdef DEBUG + printf(" segment! time %f at input time %f nexttime_ %f outsize %d\n", + nexttime_ - chopsize_.get(), time, nexttime_, outsize); +#endif + /* report segment at precise last chop time */ + ret = this->propagateFrames(nexttime_ - chopsize_.get(), weight, &outputvalues_[0], outsize, 1); + + if (ret != 0) + return ret; + + nexttime_ += chopsize_.get(); // never called when not chopping + } + + /* feed temporal modelling */ + /* TODO: split frame statistics between segments proportionally wrt to exact segmentation time */ + for (unsigned int i = 0; i < num; i++) + { + tempmod_.input(values, size); + values += size; + } + } + + return 0; + } + + int finalize (double inputend) + { + double duration = chopsize_.get() > 0 ? inputend - (nexttime_ - chopsize_.get()) : inputend - offset_.get(); + +#ifdef DEBUG + printf("PiPoChop finalize time %f duration %f size %ld\n", inputend, duration, outputvalues_.size()); +#endif + + if (1) // want last smaller segment? duration >= chopsize_.get()) + { + /* end of segment (new onset or below off threshold) */ + int outsize = static_cast<int>(outputvalues_.size()); + + if (report_duration_) + // calculate actual duration of last chop + outputvalues_[0] = duration; + + /* get temporal modelling */ + if (outsize > 1) + tempmod_.getValues(&outputvalues_[report_duration_], outsize - report_duration_, true); + + /* report segment */ + return this->propagateFrames(inputend - duration, 0.0, &outputvalues_[0], outsize, 1); + } + + return 0; + } +}; + +/** EMACS ** + * Local variables: + * mode: c++ + * c-basic-offset:2 + * End: + */ + +#endif + +#if CHOP_TEST +int main (int argc, char *argv[]) +{ + + + return 0; +} +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoConst.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoConst.h new file mode 100644 index 0000000000000000000000000000000000000000..54454516311469004fbfb7e3b058bc1e60701d42 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoConst.h @@ -0,0 +1,184 @@ +/** + * @file PiPoConst.h + * @author Diemo.Schwarz@ircam.fr + * + * @brief PiPo providing a constant value + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012 by IMTR IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_CONST_ +#define _PIPO_CONST_ + +#define CONST_DEBUG DEBUG*1 + +#include "PiPo.h" + +extern "C" { +#include <stdlib.h> +} + +class PiPoConst : public PiPo +{ +public: + PiPoScalarAttr<float> value; + PiPoScalarAttr<const char *> name; + + PiPoConst (Parent *parent, PiPo *receiver = NULL); + ~PiPoConst (void); + + int streamAttributes (bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int size, const char **labels, + bool hasVarSize, double domain, unsigned int maxFrames); + int finalize (double inputEnd); + int reset (void); + int frames (double time, double weight, float *values, unsigned int size, unsigned int num); + +private: + int numcols_; + PiPoValue *values_; +}; + + +inline PiPoConst::PiPoConst (Parent *parent, PiPo *receiver) +: PiPo(parent, receiver), + value(this, "value", "value to store for added column", false, 0), + name(this, "name", "name of added column", true, "Constant"), + numcols_(0), values_(NULL) +{} + +inline PiPoConst::~PiPoConst(void) +{ +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// init module +// + +inline int PiPoConst::streamAttributes (bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int size, + const char **labels, bool hasVarSize, + double domain, unsigned int maxFrames) +{ +#if CONST_DEBUG >= 2 + printf("PiPoConst streamAttributes timetags %d rate %f offset %f width %d size %d labels %s varsize %d domain %f maxframes %d\n", + hasTimeTags, rate, offset, width, size, labels ? labels[0] : "n/a", hasVarSize, domain, maxFrames); + +#endif + +# define MAX_DESCR_NAME 64 + numcols_ = width + 1; + values_ = (PiPoValue *) realloc(values_, maxFrames * size * numcols_ * sizeof(PiPoValue)); // alloc space for maxmal block size + + /* get labels */ + char *mem = new char[numcols_ * MAX_DESCR_NAME]; + char **outlabels = new char*[numcols_]; + + for (int i = 0; i < numcols_; i++) + outlabels[i] = mem + i * MAX_DESCR_NAME; + + // copy input labels plus one more + if (labels != NULL) + memcpy(outlabels, labels, width * sizeof(char *)); + else // no input labels given, invent one + for(unsigned int i = 0; i < width; i++) + outlabels[i] = (char *)"unnamed"; + strncpy(outlabels[numcols_ - 1], name.get(), MAX_DESCR_NAME); + + int ret = this->propagateStreamAttributes(hasTimeTags, rate, offset, numcols_, 1, + (const char **) &outlabels[0], false, domain, 1); + + delete [] mem; + delete [] outlabels; + + return ret; +} + +inline int PiPoConst::finalize (double inputEnd) +{ + //post("PiPoConst finalize %f\n", inputEnd); + return this->propagateFinalize(inputEnd); +}; + + +inline int PiPoConst::reset (void) +{ + //post("PiPoConst reset\n"); + return this->propagateReset(); +}; + + +/////////////////////////////////////////////////////////////////////////////// +// +// compute and output data +// + +inline int PiPoConst::frames (double time, double weight, float *invalues, unsigned int size, unsigned int num) +{ + int status = 0; + int nincols = numcols_ - 1; // num input columns + int ninrows = size / nincols; + float *outvalues = values_; + float constvalue = value.get(); + +#if CONST_DEBUG >= 2 + printf("PiPoConst::frames time %f values %p size %d num %d --> %f\n", + time, invalues, size, num, constvalue); +#endif + + for (unsigned int i = 0; i < num; i++) + { + for (int j = 0; j < ninrows; j++) + { // copy line by line + memcpy(outvalues, invalues, nincols * sizeof(float)); + outvalues[numcols_ - 1] = constvalue; + + outvalues += numcols_; + invalues += nincols; + } + } + + status = propagateFrames(time, weight, values_, ninrows * numcols_, num); + return status; +} + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif /* _PIPO_CONST_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoDct.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoDct.h new file mode 100644 index 0000000000000000000000000000000000000000..e3071d2a3798eb619619dc1a4a964caeb5d7de13 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoDct.h @@ -0,0 +1,145 @@ +/** + * @file PiPoDct.h + * @author Norbert.Schnell@ircam.fr + * + * @brief RTA DCT PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_DCT_ +#define _PIPO_DCT_ + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_dct.h" +} + +#include <vector> + +class PiPoDct : public PiPo +{ +public: + enum WeightingMode { PlpMode, SlaneyMode, HtkMode, FeacalcMode }; + +private: + std::vector<float> frame; + std::vector<float> weights; + unsigned int inputSize; + enum WeightingMode weightingMode; + +public: + PiPoScalarAttr<int> order; + PiPoScalarAttr<PiPo::Enumerate> weighting; + + PiPoDct(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + frame(), weights(), + weighting(this, "weighting", "DCT Weighting Mode", true, FeacalcMode), + order(this, "order", "DCT Order", true, 12) + { + this->inputSize = 0; + this->weightingMode = FeacalcMode; + + this->weighting.addEnumItem("plp", "plp weighting"); + this->weighting.addEnumItem("slaney", "slaney weighting"); + this->weighting.addEnumItem("htk", "HTK weighting"); + this->weighting.addEnumItem("feacalc", "feacalc weighting"); + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int order = this->order.get(); + unsigned int inputSize = width * size; + + enum WeightingMode weightingMode = (enum WeightingMode)this->weighting.get(); + if(weightingMode > FeacalcMode) { + weightingMode = FeacalcMode; + } + + if(order != this->frame.size() || inputSize != this->inputSize || weightingMode != this->weightingMode) + { + this->frame.resize(order); + this->weights.resize(inputSize * order); + this->inputSize = inputSize; + + switch(weightingMode) + { + case PlpMode: + rta_dct_weights(&this->weights[0], inputSize, order, rta_dct_plp); + break; + + case SlaneyMode: + rta_dct_weights(&this->weights[0], inputSize, order, rta_dct_slaney); + break; + + case HtkMode: + rta_dct_weights(&this->weights[0], inputSize, order, rta_dct_htk); + break; + + case FeacalcMode: + rta_dct_weights(&this->weights[0], inputSize, order, rta_dct_feacalc); + break; + } + + this->weightingMode = weightingMode; + + //rta_dct_weights(&this->weights[0], inputSize, order, rta_dct_feacalc); + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, order, 1, NULL, 0, 0.0, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + for(unsigned int i = 0; i < num; i++) + { + rta_dct(&this->frame[0], values, &this->weights[0], this->inputSize, + static_cast<unsigned int>(this->frame.size())); + + int ret = this->propagateFrames(time, weight, &this->frame[0], + static_cast<unsigned int>(this->frame.size()), 1); + + if(ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoDelta.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoDelta.h new file mode 100644 index 0000000000000000000000000000000000000000..bd2c4727a5f40aa95e6b6daef91c49d3ab1eb0ac --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoDelta.h @@ -0,0 +1,203 @@ +/** + * @file PiPoDelta.h + * @author Diemo Schwarz + * + * @brief PiPo calculating delta values on a stream + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2014 by ISMM IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_DELTA_ +#define _PIPO_DELTA_ + +#include "PiPo.h" +#include "RingBuffer.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_delta.h" +} + +#include <vector> +#include <cstdlib> + +class PiPoDelta : public PiPo +{ + RingBuffer<PiPoValue> buffer; + std::vector<PiPoValue> weights; + std::vector<PiPoValue> frame; + unsigned int filter_size; + unsigned int input_size; + unsigned int missing_inputs; + PiPoValue normalization_factor; + +public: + PiPoScalarAttr<int> filter_size_param; + PiPoScalarAttr<bool> normalize; + + PiPoDelta (Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + buffer(), weights(), frame(), + filter_size(0), input_size(0), missing_inputs(0), normalization_factor(1), + filter_size_param(this, "size", "Filter Size", true, 7), + normalize(this, "normalize", "Normalize output", true, true) + { } + + ~PiPoDelta () + { } + + int streamAttributes (bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int size, + const char **labels, bool hasVarSize, double domain, + unsigned int maxFrames) + { + unsigned int filtsize = filter_size_param.get(); + unsigned int insize = width * size; + + if (filtsize != filter_size || insize != input_size) + { + if (filtsize < 3) + { + //todo: report pipo_error("filter size must be >= 3"); + filtsize = 3; + } + else if ((filtsize & 1) == 0) // even filtersize, must be odd + { + //todo: pipo_error("filter size must be odd: using %d instead of %d", filtsize - 1, filtsize); + filtsize--; + } + + unsigned int filter_delay = filtsize / 2; // center, filter_size is odd + + // ring size is the maximum between filter size and added delays + // (plus the past input to be reoutput) + int ring_size = filtsize > filter_delay + 1 + ? filtsize : filter_delay + 1; + + buffer.resize(insize, ring_size); + frame.resize(insize); + + // weights_vector zero-padded to fit the ring size (before the + // values) and then duplicated to be applied strait to the inputs + // ring buffer, so actual memory size is ring_size * 2 + weights.resize(ring_size * 2); + std::fill(&weights[0], &weights[ring_size - filtsize], 0.); + rta_delta_weights(&weights[ring_size - filtsize], filtsize); + + // duplicate (unroll) weights for contiguous indexing + //C++11: std::copy_n(weights.begin(), filtsize, weights.begin() + filtsize); + for (int i = 0; i < ring_size; i++) + weights[i + ring_size] = weights[i]; + + normalization_factor = rta_delta_normalization_factor(filtsize); + filter_size = filtsize; + input_size = insize; + } + + offset -= 1000.0 * 0.5 * (filtsize - 1) / rate; + + char **dlab = new char*[width]; + const char **newlab = NULL; + + if (labels) + { // prefix labels with "Delta" +# define prefix "Delta" + + for (unsigned int i = 0; i < width; i++) + { + dlab[i] = (char *) malloc(strlen(prefix) + (labels[i] ? strlen(labels[i]) : 0) + 1); + sprintf(dlab[i], prefix "%s", labels[i]); + } + + newlab = (const char **) dlab; + } + + int ret = propagateStreamAttributes(hasTimeTags, rate, offset, insize, + 1, newlab, 0, 0.0, 1); + + if (labels) + for (unsigned int i = 0; i < width; i++) + free(dlab[i]); + delete[] dlab; + return ret; + } + + int reset () + { + buffer.reset(); + return propagateReset(); + }; + + int frames (double time, double weight, float *values, unsigned int size, unsigned int num) + { + int ret = 0; + + for (unsigned int i = 0; i < num; i++) + { + buffer.input(values, size); + + if (buffer.filled) + { + float *wptr = &weights[buffer.size - buffer.index]; + + rta_delta_vector(&frame[0], &buffer.vector[0], buffer.width, wptr, buffer.size); + + if (normalize.get()) + { + for (unsigned int i = 0; i < size; i++) + frame[i] *= normalization_factor; + } + + ret = this->propagateFrames(time, weight, &frame[0], + static_cast<unsigned int>(frame.size()), 1); + } + + if (ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif /* _PIPO_DELTA_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoFft.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoFft.h new file mode 100644 index 0000000000000000000000000000000000000000..1d71dad2e04099ebf4b8fb53d4c0d4cd563b0112 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoFft.h @@ -0,0 +1,496 @@ +/** + * @file PiPoFft.h + * @author Norbert.Schnell@ircam.fr + * + * @brief RTA FFT PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_FFT_ +#define _PIPO_FFT_ + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_fft.h" +#include "rta_int.h" +#include <float.h> +#include <math.h> +} + +#define MIN_FFT_SIZE 16 +#define MAX_FFT_SIZE 65536 +#define DB_TO_LIN(x) (exp(0.115129254649702 * x)) + +static const double itur468Coeffs[21][2] = { + {31.5, -29.9}, + {63.0, -23.9}, + {100.0, -19.8}, + {200.0, -13.8}, + {400.0, -7.8}, + {800.0, -1.9}, + {1000.0, 0.0}, + {2000.0, 5.6}, + {3150.0, 9.0}, + {4000.0, 10.5}, + {5000.0, 11.7}, + {6300.0, 12.2}, + {7100.0, 12.0}, + {8000.0, 11.4}, + {9000.0, 10.1}, + {10000.0, 8.1}, + {12500.0, 0.0}, + {14000.0, -5.3}, + {16000.0, -11.7}, + {20000.0, -22.2}, + {31500.0, -42.7} +}; + +#include <vector> + +static int +getClosestItur468Index(double freq) +{ + for(int i = 0; i < 21; i++) + { + if(freq < itur468Coeffs[i][0]) + return i - 1; + } + + return 19; +} + +static double +getItur468Factor(double freq) +{ + int index = getClosestItur468Index(freq); + double levl = 0.0; + + if(index < 0) + { + double freq0 = itur468Coeffs[0][0]; + double levl0 = itur468Coeffs[0][1]; + + levl = levl0 + log2(freq / freq0) * 6.0; + } + else + { + double freq0 = itur468Coeffs[index][0]; + double freq1 = itur468Coeffs[index + 1][0]; + double levl0 = itur468Coeffs[index][1]; + double levl1 = itur468Coeffs[index + 1][1]; + + levl = levl0 + (freq - freq0) * (levl1 - levl0) / (freq1 - freq0); + } + + return DB_TO_LIN(levl); +} + +class PiPoFft : public PiPo +{ +public: + enum OutputMode { ComplexFft, MagnitudeFft, PowerFft, LogPowerFft }; + enum WeightingMode { NoWeighting, AWeighting, BWeighting, CWeighting, DWeighting, Itur468Weighting}; + + std::vector<float> fftFrame; + std::vector<float> fftWeights; + double sampleRate; + int fftSize; + enum OutputMode outputMode; + enum WeightingMode weightingMode; + rta_fft_setup_t *fftSetup; + float fftScale; + +public: + PiPoScalarAttr<int> size; + PiPoScalarAttr<PiPo::Enumerate> mode; + PiPoScalarAttr<bool> norm; + PiPoScalarAttr<PiPo::Enumerate> weighting; + + PiPoFft(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + fftFrame(), + fftWeights(), + size(this, "size", "FFT Size", true, 0), + mode(this, "mode", "FFT Mode", true, PowerFft), + norm(this, "norm", "Normalize FFT", true, true), + weighting(this, "weighting", "FFT Weighting", true, NoWeighting) + { + this->sampleRate = 1.0; + this->fftSize = 0; + this->outputMode = PowerFft; + this->weightingMode = NoWeighting; + this->fftSetup = NULL; + this->fftScale = 1.0; + + this->mode.addEnumItem("complex", "Complex output"); + this->mode.addEnumItem("magnitude", "Magnitude spectrum"); + this->mode.addEnumItem("power", "Power spectrum"); + this->mode.addEnumItem("logpower", "Logarithmic power spectrum"); + + this->weighting.addEnumItem("none", "No weighting"); + this->weighting.addEnumItem("a", "dB-A weighting"); + this->weighting.addEnumItem("b", "dB-B weighting"); + this->weighting.addEnumItem("c", "dB-C weighting"); + this->weighting.addEnumItem("d", "dB-C weighting"); + this->weighting.addEnumItem("itur468", "ITU-R 468 weighting"); + } + + ~PiPoFft(void) + { + if(this->fftSetup != NULL) + rta_fft_setup_delete(this->fftSetup); + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + int fftSize = this->size.get(); + enum OutputMode outputMode = (enum OutputMode)this->mode.get(); + bool norm = this->norm.get(); + enum WeightingMode weightingMode = (enum WeightingMode)this->weighting.get(); + int inputSize = width * size; + double sampleRate = (double)size / domain; + int outputSize, outputWidth; + const char *fftColNames[2]; + + if(fftSize <= 0) + fftSize = rta_inextpow2(inputSize); + else if(fftSize > MAX_FFT_SIZE) + fftSize = MAX_FFT_SIZE; + + if(norm) + this->fftScale = 1.0 / fftSize; + else + this->fftScale = 1.0; + + outputSize = fftSize / 2; + + if(outputMode > LogPowerFft) + outputMode = LogPowerFft; + + if(weightingMode > Itur468Weighting) + weightingMode = Itur468Weighting; + + this->sampleRate = sampleRate; + + switch(outputMode) + { + case ComplexFft: + { + fftColNames[0] = "Real"; + fftColNames[1] = "Imag"; + outputWidth = 2; + break; + } + + case MagnitudeFft: + { + fftColNames[0] = "Magnitude"; + outputWidth = 1; + break; + } + + case PowerFft: + { + fftColNames[0] = "Power"; + outputWidth = 1; + break; + } + + case LogPowerFft: + { + fftColNames[0] = "LogPower"; + outputWidth = 1; + break; + } + } + + if(fftSize != this->fftSize || weightingMode != this->weightingMode) + { + float *nyquistMagPtr; + + /* alloc output frame */ + this->fftFrame.resize(fftSize + 2); + this->fftWeights.resize(outputSize + 1); + this->fftSize = fftSize; + + nyquistMagPtr = &this->fftFrame[fftSize]; + this->fftFrame[fftSize + 1] = 0.0; /* zero nyquist phase */ + + double indexToFreq = sampleRate / fftSize; + + switch(weightingMode) + { + case NoWeighting: + { + for(int i = 0; i <= outputSize; i++) + this->fftWeights[i] = 1.0f; + + break; + } + + case AWeighting: + { + static const double weightScale = 1.258953930848941; + + this->fftWeights[0] = 0.0; + + for(int i = 1; i <= outputSize; i++) + { + double freq = indexToFreq * i; + double fsq = freq * freq; + double w = fsq * fsq * 12200.0 * 12200.0 / ((fsq + 20.6 * 20.6) * (fsq + 12200.0 * 12200.0) * sqrt((fsq + 107.7 * 107.7) * (fsq + 737.9 * 737.9))); + this->fftWeights[i] = (float)(w * weightScale); + } + + break; + } + + case BWeighting: + { + static const double weightScale = 1.019724962918924; + + this->fftWeights[0] = 0.0; + + for(int i = 1; i <= outputSize; i++) + { + double freq = indexToFreq * i; + double fsq = freq * freq; + double w = freq * fsq * 12200.0 * 12200 / ((fsq + 20.6 * 20.6) * sqrt(fsq + 158.5 * 158.5) * (fsq + 12200 * 12200)); + this->fftWeights[i] = (float)(w * weightScale); + } + + break; + } + + case CWeighting: + { + static const double weightScale = 1.007146464025963; + + this->fftWeights[0] = 0.0; + + for(int i = 1; i <= outputSize; i++) + { + double freq = indexToFreq * i; + double fsq = freq * freq; + double w = fsq * 12200.0 * 12200.0 / ((fsq + 20.6 * 20.6) * (fsq + 12200.0 * 12200.0)); + this->fftWeights[i] = (float)(w * weightScale); + } + + break; + } + + case DWeighting: + { + static const double weightScale = 0.999730463675085; + + this->fftWeights[0] = 0.0; + + for(int i = 1; i <= outputSize; i++) + { + double freq = indexToFreq * i; + double fsq = freq * freq; + double n1 = 1037918.48 - fsq; + double n2 = 1080768.16 * fsq; + double d1 = 9837328.0 - fsq; + double d2 = 11723776.0 * fsq; + double h = (n1 * n1 + n2) / (d1 * d1 + d2); + double w = 14499.711699348260202 * freq * sqrt(h / ((fsq + 79919.29) * (fsq + 1345600.0))); + this->fftWeights[i] = (float)(w * weightScale); + } + + break; + } + + case Itur468Weighting: + { + this->fftWeights[0] = 0.0; + + for(int i = 1; i <= outputSize; i++) + { + double freq = indexToFreq * i; + this->fftWeights[i] = (float)getItur468Factor(freq); + } + + break; + } + } + + /* setup FFT */ + if(this->fftSetup != NULL) + rta_fft_setup_delete(this->fftSetup); + + rta_fft_real_setup_new(&this->fftSetup, rta_fft_real_to_complex_1d, (float *)&this->fftScale, NULL, inputSize, &this->fftFrame[0], fftSize, nyquistMagPtr); + } + + this->outputMode = outputMode; + this->weightingMode = weightingMode; + + return this->propagateStreamAttributes(0, rate, offset, outputWidth, outputSize + 1, fftColNames, 0, 0.5 * sampleRate, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + if(this->fftSetup != NULL) + { + float *fftFrame = &this->fftFrame[0]; + unsigned int outputMode = this->outputMode; + int fftSize = this->fftSize; + int outputSize = fftSize / 2; + float *outputFrame; + int outputWidth; + + if(outputMode > LogPowerFft) + outputMode = LogPowerFft; + + for(unsigned int i = 0; i < num; i++) + { + rta_fft_execute(fftFrame, values, size, this->fftSetup); + + switch(outputMode) + { + case ComplexFft: + { + outputWidth = 2; + outputFrame = fftFrame; + + /* apply weighting */ + if(this->weightingMode != NoWeighting) + { + for(int i = 0; i <= outputSize; i++) + { + outputFrame[2 * i] *= this->fftWeights[i]; + outputFrame[2 * i + 1] *= this->fftWeights[i]; + } + } + + break; + } + + case MagnitudeFft: + { + float re, im; + + outputWidth = 1; + outputFrame = &this->fftFrame[outputSize]; + + re = fftFrame[outputSize * 2]; + im = fftFrame[outputSize * 2 + 1]; + outputFrame[outputSize] = sqrtf(re * re + im * im) * this->fftWeights[outputSize]; + + for(int i = outputSize - 1; i > 0; i--) + { + re = fftFrame[i * 2]; + im = fftFrame[i * 2 + 1]; + outputFrame[i] = 2 * sqrtf(re * re + im * im) * this->fftWeights[i]; + } + + re = fftFrame[0]; + im = fftFrame[1]; + outputFrame[i] = sqrtf(re * re + im * im) * this->fftWeights[outputSize]; + + break; + } + + case PowerFft: + { + float re, im; + + outputWidth = 1; + outputFrame = &this->fftFrame[outputSize]; + + re = fftFrame[outputSize * 2] * this->fftWeights[outputSize]; + im = fftFrame[outputSize * 2 + 1] * this->fftWeights[outputSize]; + outputFrame[outputSize] = re * re + im * im; + + for(int i = outputSize - 1; i > 0; i--) + { + re = fftFrame[i * 2] * this->fftWeights[i]; + im = fftFrame[i * 2 + 1] * this->fftWeights[i]; + outputFrame[i] = 4 * (re * re + im * im); + } + + re = fftFrame[0] * this->fftWeights[0]; + im = fftFrame[1] * this->fftWeights[0]; + outputFrame[0] = re * re + im * im; + + break; + } + + case LogPowerFft: + { + const double minLogValue = 1e-48; + const double minLog = -480.0; + float re, im, pow; + + outputWidth = 1; + outputFrame = &this->fftFrame[outputSize]; + + re = fftFrame[outputSize * 2] * this->fftWeights[outputSize]; + im = fftFrame[outputSize * 2 + 1] * this->fftWeights[outputSize]; + pow = re * re + im * im; + + outputFrame[outputSize] = ((pow > minLogValue)? (10.0f * log10f(pow)): minLog); + + for(int i = outputSize - 1; i > 0; i--) + { + re = fftFrame[i * 2] * this->fftWeights[i]; + im = fftFrame[i * 2 + 1] * this->fftWeights[i]; + pow = re * re + im * im; + outputFrame[i] = ((pow > minLogValue)? (10.0f * log10f(pow)): minLog); + } + + re = fftFrame[0] * this->fftWeights[0]; + im = fftFrame[1] * this->fftWeights[0]; + pow = re * re + im * im; + outputFrame[0] = ((pow > minLogValue)? (10.0f * log10f(pow)): minLog); + + break; + } + } + + int ret = this->propagateFrames(time, weight, outputFrame, outputWidth * (outputSize + 1), 1); + + if(ret != 0) + return ret; + + values += size; + } + } + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoFiniteDif.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoFiniteDif.h new file mode 100644 index 0000000000000000000000000000000000000000..e0ac7aaa644994cf14ac0732361c684ca13e3036 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoFiniteDif.h @@ -0,0 +1,474 @@ +/** + * @file PiPoFiniteDif.h + * @author Gaël Dubus + * + * @brief PiPo calculating various derivative values on a stream using the finite difference method + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2015 by ISMM IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_FINITE_DIF_ +#define _PIPO_FINITE_DIF_ + +#include "PiPo.h" +#include "RingBuffer.h" +#include <sstream> + +extern "C" { + //#include "rta_configuration.h" +#include "finitedifferences.h" +} + +#include <vector> + +class PiPoFiniteDif : public PiPo { + private: + RingBuffer<PiPoValue> buffer; + std::vector<PiPoValue> weights; + std::vector<PiPoValue> frame; + int filter_size; + int input_size; + //unsigned int missing_inputs; + //PiPoValue normalization_factor; + int accuracy_order; + int derivative_order; + FDMethod method; + public: + PiPoScalarAttr<int> filter_size_param; + PiPoScalarAttr<bool> temporalize; + PiPoScalarAttr<int> derivative_order_param; + PiPoScalarAttr<int> accuracy_order_param; + PiPoScalarAttr<float> delta_t; + PiPoScalarAttr<PiPo::Enumerate> fdmethod; + + PiPoFiniteDif (Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + buffer(), + weights(), + frame(), + filter_size(0), + input_size(0), + //missing_inputs(0), + //normalization_factor(1), + accuracy_order(1), + derivative_order(1), + method(Backward), + filter_size_param(this, "size", "Filter Size", true, 3), + //normalize(this, "normalize", "Normalize output", true, false), + derivative_order_param(this, "order", "Derivative order", true, 1), + accuracy_order_param(this, "accuracy", "Accuracy order", true, 2), + delta_t(this, "dt", "Sampling period", true, 0.01), + fdmethod(this, "method", "Finite difference method", true, Backward), + temporalize(this, "temporalize", "Take into account the sample rate in the computation", false, false) + { + this->fdmethod.addEnumItem("backward", "Backward FD"); + this->fdmethod.addEnumItem("centered", "Centered FD"); + this->fdmethod.addEnumItem("forward", "Forward FD"); + } + + ~PiPoFiniteDif () + { } + + int streamAttributes (bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames){ + int filtsize = filter_size_param.get(); + int deriv_order = derivative_order_param.get(); + int accur_order = accuracy_order_param.get(); + int insize = width * size; + FDMethod meth = (FDMethod)fdmethod.get(); + std::ostringstream error_message; + int temp; + int filter_delay = 0; + + bool debug = false; + + if (debug) + { + error_message << "In: filter_size = " << filter_size << ", input_size = " << input_size << ", accuracy_order = " << accuracy_order << ", derivative_order = " << derivative_order << ", method = " << method; + signalWarning(error_message.str()); + error_message.str(""); + error_message << "Inner parameters: filtsize = " << filtsize << ", insize = " << insize << ", accur_order = " << accur_order << ", deriv_order = " << deriv_order << ", meth = " << meth; + signalWarning(error_message.str()); + error_message.str(""); + } + //Important parameter change -> reinitialization + if (meth != method || deriv_order != derivative_order || + accur_order != accuracy_order || filtsize != filter_size || + insize != input_size) + { + + //First, check and update method, deriv_order, accur_order, filtsize + //Verifications to perform in all cases + if (deriv_order != derivative_order && deriv_order < 1) + { + signalWarning("derivation order must be >= 1, set to 1"); + deriv_order = 1; + } + + //Verifications depending on the method + switch (meth) + { + case Centered: + //Derivative order has changed + if (deriv_order != derivative_order) + { + if (deriv_order > 6) + { + signalWarning("derivation order must be <= 6 for a centered method, set to 6"); + deriv_order = 6; + } + } + + //Modification by filter size (or by both filter size and accuracy order) (or derivative order has changed) (or method) + if (deriv_order != derivative_order || meth != method || filtsize != filter_size) + { + //New filter size should be odd + if ((filtsize & 1) == 0) + { + error_message << "filter size must be odd: using " << filtsize-1 << " instead of " << filtsize; + signalWarning(error_message.str()); + error_message.str(""); + filtsize--; + } + + //Check that the filter size lies within acceptable bounds + temp = 3 + 2 * ((deriv_order - 1) / 2); + + if (filtsize < temp) + { + error_message << "filter size must be >= " << temp << " for a centered method with derivation order " << deriv_order << ", set to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + filtsize = temp; + } + else + { + temp = 9 - 2 * ((deriv_order - 1) / 4); + + if (filtsize > temp) + { + error_message << "filter size must be <=" << temp << " for a centered method with derivation order " << deriv_order << ", set to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + filtsize = temp; + } + } + + //Update accuracy order + temp = filtersize_to_accuracy(meth, deriv_order, filtsize); + + //If both filter size and accuracy order were provided, check that they are compatible + //if (accur_order != accuracy_order && temp != accur_order){ + if (temp != accur_order) + { + error_message << "accuracy order updated to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + } + + accur_order = temp; + } + //Modification by accuracy order (only) + else + { + //New accuracy order should be even + if ((accur_order & 1) == 1) + { + error_message << "accuracy order must be even for a centered method: using " << accur_order-1 << " instead of " << accur_order; + signalWarning(error_message.str()); + error_message.str(""); + accur_order--; + } + + if (accur_order != accuracy_order) + { + //Check that accuracy order lies within acceptable bounds + if (accur_order < 2) + { + signalWarning("accuracy order must be >= 2, set to 2"); + accur_order = 2; + } + else + { + temp = 8 - ((deriv_order - 1) / 2) * ((deriv_order + 1) / 2); + + if (accur_order > temp) + { + error_message << "accuracy order must be <=" << temp << " for a centered method with derivation order " << deriv_order << ", set to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + accur_order = temp; + } + } + } + + //Update filter size + filtsize = accuracy_to_filtersize(meth, deriv_order, accur_order); + + if (filter_size != filtsize) + { + error_message << "filter size updated to " << filtsize; + signalWarning(error_message.str()); + error_message.str(""); + } + } + break; + + case Forward: + case Backward: + if (deriv_order > 4) + { + signalWarning("derivation order must be <= 4 for a backward or forward method, set to 4"); + deriv_order = 4; + } + + //Modification by filter size (or by both filter size and accuracy order) (or derivative order has changed) + if (deriv_order != derivative_order || meth != method || filtsize != filter_size) + { + //Check that the filter size lies within acceptable bounds + temp = deriv_order + 1; + + if (filtsize < temp) + { + error_message << "filter size must be >= " << temp << " for a backward or forward method with derivation order " << deriv_order << ", set to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + filtsize = temp; + } + else + { + temp = 6 + deriv_order - deriv_order / 4; + + if (filtsize > temp) + { + error_message << "filter size must be <=" << temp << " for a backward or forward method with derivation order " << deriv_order << ", set to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + filtsize = temp; + } + } + + //Update accuracy order + temp = filtersize_to_accuracy(meth, deriv_order, filtsize); + + //If both filter size and accuracy order were provided, check that they are compatible + //if (accur_order != accuracy_order && temp != accur_order){ + if (temp != accur_order) + { + error_message << "accuracy order updated to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + } + + accur_order = temp; + } + //Modification by accuracy order (only) + else + { + if (accur_order != accuracy_order) + { + //Check that accuracy order lies within acceptable bounds + if (accur_order < 1) + { + signalWarning("accuracy order must be >= 1, set to 1"); + accur_order = 1; + } + else + { + temp = 6 - deriv_order / 4; + if (accur_order > temp) + { + error_message << "accuracy order must be <=" << temp << " for a backward or forward method with derivation order " << deriv_order << ", set to " << temp; + signalWarning(error_message.str()); + error_message.str(""); + accur_order = temp; + } + } + + //Update filter size + filtsize = accuracy_to_filtersize(meth, deriv_order, accur_order); + + if (filter_size != filtsize) + { + error_message << "filter size updated to " << filtsize; + signalWarning(error_message.str()); + error_message.str(""); + } + } + } + break; + + default: + signalWarning("unknown method, set to Backward"); + meth = Backward; + break; + } + + // compute filter delay + switch (meth) + { + case Centered: + filter_delay = filtsize/2; + break; + + case Backward: + filter_delay = 0; + break; + + case Forward: + filter_delay = filtsize-1; + break; + + default: + signalError("unknown method"); + break; + } + + // ring size is the maximum between filter size and added delays + // (plus the past input to be reoutput) + int ring_size = filtsize > filter_delay + 1 + ? filtsize + : filter_delay + 1; + + buffer.resize(insize, ring_size); + frame.resize(insize); + + // weights_vector zero-padded to fit the ring size (before the + // values) and then duplicated to be applied strait to the inputs + // ring buffer, so actual memory size is ring_size * 2 + weights.resize(ring_size * 2); + std::fill(&weights[0], &weights[ring_size - filtsize], 0.); + finitedifferences_weights_by_filtersize(&weights[ring_size - filtsize], deriv_order, filtsize, meth); + + // duplicate (unroll) weights for contiguous indexing + //C++11: std::copy_n(weights.begin(), filtsize, weights.begin() + filtsize); + for (int i = 0; i < ring_size; i++) + weights[i + ring_size] = weights[i]; + + //normalization_factor = 1.;//finitedifferences_normalization_factor(filtsize, meth, accur_order) + //update private variables + filter_size = filtsize; + input_size = insize; + accuracy_order = accur_order; + derivative_order = deriv_order; + method = meth; + //update pipo parameters silently + filter_size_param.set(filtsize, true); + accuracy_order_param.set(accur_order, true); + derivative_order_param.set(deriv_order, true); + fdmethod.set(meth, true); + + if (debug) + { + error_message << "Out: filter size = " << filter_size << ", input size = " << input_size << ", accuracy order = " << accuracy_order << ", derivative order = " << derivative_order << ", method = " << method; + signalError(error_message.str()); + error_message.str(""); + } + } + + //offset -= 1000.0 * 0.5 * (filtsize - 1) / rate; + offset -= 1000.0 * filter_delay / rate; + + char **dlab = new char*[width]; + const char **newlab = NULL; + + if (labels) + { // prefix labels with "Delta" +#define prefix "Delta" + + for (unsigned int i = 0; i < width; i++) + { + dlab[i] = (char *) malloc(strlen(prefix) + (labels[i] ? strlen(labels[i]) : 0) + 1); + sprintf(dlab[i], prefix "%s", labels[i]); + } + + newlab = (const char **) dlab; + } + + int ret = propagateStreamAttributes(hasTimeTags, rate, offset, insize, + 1, newlab, 0, 0.0, 1); + + if (labels) + for (unsigned int i = 0; i < width; i++) + + free(dlab[i]); + delete[] dlab; + return ret; + } + + int reset () + { + buffer.reset(); + return propagateReset(); + }; + + int frames (double time, double weight, float *values, unsigned int size, unsigned int num){ + int ret = 0; + + for (unsigned int i = 0; i < num; i++) + { + buffer.input(values, size); + + if (buffer.filled) + { + float *wptr = &weights[buffer.size - buffer.index]; + finitedifferences_vector(&frame[0], &buffer.vector[0], buffer.width, wptr, buffer.size); + + // if (normalize.get()) + // { + // for (int i = 0; i < size; i++) + // frame[i] *= normalization_factor; + // } + + ret = this->propagateFrames(time, weight, &frame[0], + static_cast<unsigned int>(frame.size()), 1); + } + + if (ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif /* _PIPO_FINITE_DIFFERENCE_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoGate.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoGate.h new file mode 100644 index 0000000000000000000000000000000000000000..dcc5f7fb23be90bc35505607b763bfd64ee0dfa5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoGate.h @@ -0,0 +1,294 @@ +/** + * @file PiPoGate.h + * @author Diemo.Schwarz@ircam.fr + * + * @brief PiPo calculating silence segmentation by on/off threshold gating + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_GATE_ +#define _PIPO_GATE_ + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_selection.h" +} + +#include "TempMod.h" +#include <vector> +#include <string> + +class PiPoGate : public PiPo +{ + +public: + PiPoScalarAttr<int> colindex; + PiPoScalarAttr<int> numcols; + PiPoScalarAttr<double> threshold; + PiPoScalarAttr<double> offthresh; + PiPoScalarAttr<double> mininter; + PiPoScalarAttr<bool> duration; + PiPoScalarAttr<double> durthresh; + PiPoScalarAttr<double> maxsegsize; + PiPoScalarAttr<bool> enable_min; + PiPoScalarAttr<bool> enable_max; + PiPoScalarAttr<bool> enable_mean; + PiPoScalarAttr<bool> enable_stddev; + +private: + double offset; + double frameperiod; + double onsettime; + bool reportduration; + bool segison; + TempModArray tempmod; + std::vector<PiPoValue> outputvalues; + +public: + PiPoGate (Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + tempmod(), outputvalues(), + colindex(this, "colindex", "Index of First Column Used for Onset Calculation", true, 0), + numcols(this, "numcols", "Number of Columns Used for Onset Calculation", true, -1), + duration(this, "duration", "Output Segment Duration", true, false), + threshold(this, "threshold", "Onset Threshold", false, -12), + offthresh(this, "offthresh", "Segment End Threshold", false, -80), + mininter(this, "mininter", "Minimum Onset Interval", false, 50.0), + durthresh(this, "durthresh", "Minumum Segment Duration", false, 0.0), + maxsegsize(this, "maxdur", "Maximum Segment Duration", false, 0.0), + enable_min(this, "min", "Calculate Segment Min", true, false), + enable_max(this, "max", "Calculate Segment Max", true, false), + enable_mean(this, "mean", "Calculate Segment Mean", true, false), + enable_stddev(this, "stddev", "Calculate Segment StdDev", true, false) + { + this->offset = 0.0; + this->frameperiod = 1.; + this->onsettime = 0; + + this->reportduration = false; + this->segison = false; + } + + ~PiPoGate (void) + { } + + int streamAttributes (bool hastimetags, double rate, double offset, + unsigned int width, unsigned int size, const char **labels, + bool hasvarsize, double domain, unsigned int maxframes) + { + int inputsize = width; + + this->frameperiod = 1000.0 / rate; + this->offset = -this->frameperiod; // offset of negative frame period to include signal just before peak + this->onsettime = 0; + this->reportduration = this->duration.get(); + + if (this->reportduration) + { + /* resize temporal models */ + this->tempmod.resize(inputsize); + + /* enable temporal models */ + this->tempmod.enable(this->enable_min.get(), this->enable_max.get(), this->enable_mean.get(), this->enable_stddev.get()); + + /* get output size */ + unsigned int outputsize = this->tempmod.getNumValues(); + + /* alloc output vector for duration and temporal modelling output */ + this->outputvalues.resize(outputsize + 1); + + /* get labels */ + char *mem = new char[outputsize * 64 + 64]; + char **outlabels = new char*[outputsize + 1]; + + for (unsigned int i = 0; i <= outputsize; i++) + outlabels[i] = mem + i * 64; + + snprintf(outlabels[0], 64, "Duration"); + this->tempmod.getLabels(labels, inputsize, &outlabels[1], 64, outputsize); + + int ret = this->propagateStreamAttributes(true, rate, 0.0, outputsize + 1, 1, + (const char **) &outlabels[0], + false, 0.0, 1); + + delete [] mem; + delete [] outlabels; + + return ret; + } + + return this->propagateStreamAttributes(true, rate, 0.0, 0, 0, NULL, false, 0.0, 1); + } + + int reset (void) + { + this->onsettime = 0; + this->segison = false; + + this->tempmod.reset(); + + return this->propagateReset(); + }; + + int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { + double onsetThreshold = this->threshold.get(); + double minimumInterval = this->mininter.get(); + double durationThreshold = this->durthresh.get(); + double offThreshold = this->offthresh.get(); + double maxsize = maxsegsize.get(); + int colindex = this->colindex.get(); + int numcols = this->numcols.get(); + int ret = 0; + bool frameisonset; + //printf("frames at %f size %d num %d\n", time, size, num); + + // clip colindex/size + //TODO: this shouldn't change at runtime, so do this in streamAttributes only + while (colindex < 0 && size > 0) + colindex += size; + + if (numcols <= 0) + numcols = size; + + if (colindex + numcols > (int) size) + numcols = size - colindex; + + for (unsigned int i = 0; i < num; i++) + { // for all frames + /* input frame */ + double energy = 0.0; + unsigned int k = colindex; + for (int j = 0; j < numcols; j++, k++) + { + energy += values[k]; + } + energy /= numcols; + + /* determine if there is an onset */ + if (this->segison) + // within segment, check for max size if given + frameisonset = maxsize > 0 && time >= this->onsettime + maxsize; + else + // within silence, check for onset (but avoid re-trigger) + frameisonset = energy > onsetThreshold && time >= this->onsettime + minimumInterval; + + if (!this->reportduration) + { /* output marker only */ + if (frameisonset) + { /* report immediate onset */ + ret = this->propagateFrames(this->offset + time, weight, NULL, 0, 1); + this->onsettime = time; + } + } + else + { // check for onset and offset (segment begin and end) + double duration = time - this->onsettime; + + // check for segment end + if (this->segison && ((energy < offThreshold && duration >= durationThreshold) + || (maxsize > 0 && time >= this->onsettime + maxsize))) + { // energy below off threshold or max segment size exceeded + int outputsize = static_cast<int>(this->outputvalues.size()); + + this->outputvalues[0] = duration; + + /* get temporal modelling */ + if (outputsize > 1) + this->tempmod.getValues(&this->outputvalues[1], outputsize - 1, true); + + /* report segment */ + ret = this->propagateFrames(this->offset + this->onsettime, weight, &this->outputvalues[0], outputsize, 1); + } + + /* segment on/off (segment has at least one frame) */ + if (frameisonset) + { + this->segison = true; + this->onsettime = time; + } + else if (energy < offThreshold) + this->segison = false; + + /* feed temporal modelling */ + if (this->segison) + this->tempmod.input(values, size); + } + + if (ret != 0) + return ret; + + values += size; + time += this->frameperiod; // increase time for next input frame (if num > 1) + } // end for all frames + + return 0; + } + + int finalize (double inputend) + { + double durationThreshold = this->durthresh.get(); + double duration = inputend - this->onsettime; + //printf("finalize at %f seg %d duration %f\n", inputEnd, segIsOn, duration); + + if (this->segison && duration >= durationThreshold) + { + /* end of segment (new onset or below off threshold) */ + int outputsize = static_cast<int>(this->outputvalues.size()); + + this->outputvalues[0] = duration; + + /* get temporal modelling */ + if (outputsize > 1) + this->tempmod.getValues(&this->outputvalues[1], outputsize - 1, true); + + /* report segment */ + return this->propagateFrames(this->offset + this->onsettime, 0.0, &this->outputvalues[0], outputsize, 1); + } + + return this->propagateFinalize(inputend); + } +}; + +/** EMACS ** + * Local variables: + * mode: c++ + * c-basic-offset:2 + * End: + */ + +#endif + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoLpc.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoLpc.h new file mode 100644 index 0000000000000000000000000000000000000000..7a27e087188b43208b0404754acd8844c2a3146f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoLpc.h @@ -0,0 +1,159 @@ +/** + * @file PiPoLpc.h + * @author Joseph Larralde + * @date 02.12.2015 + * + * @brief RTA LPC PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2015 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_LPC_H_ +#define _PIPO_LPC_H_ + +#include "PiPo.h" + +extern "C" { +#include "rta_lpc.h" +#include <stdlib.h> +} + +/** TMP NOTES : + * input is a signal (1 to N dims, as in biquad) + * outputs are list signals (1 to N lists of size XXX?), each list being the coefs characterizing the corresponding input dim + * parameters are : + * - param1 : lpc_order (nb of coeffs : order 0 -> 1 coef, order 1 -> 2 coefs etc) + * - param2 (are there other params ?) + */ + +class PiPoLpc : public PiPo +{ +//public: +private: + unsigned int frameSize; + //unsigned int nFrames; + float frameRate; + + int ac_size; + float *corr; + float error; + + unsigned int nCoefs; + float *coefs; + float *outValues; + +public: + PiPoScalarAttr<int> nCoefsA; + + //=============== CONSTRUCTOR ===============// + PiPoLpc(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + nCoefsA(this, "ncoefs", "Number Of LPC Coefficients", true, 10) + { + this->frameSize = 0; + //this->nFrames = 0; + this->frameRate = 1.; + + this->nCoefs = 0; + this->coefs = NULL; + this->corr = NULL; + //this->outValues = NULL; + + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int frameSize = width * size; + //unsigned int nFrames = 1;//size; + unsigned int nCoefs = this->nCoefsA.get(); + + if(rate != this->frameRate) { + this->frameRate = rate; + } + + /* + if(frameSize != this->frameSize) { + this->frameSize = frameSize; + // resize outValues array + this->outValues = (float *)realloc(this->outValues, this->nFrames * this->frameSize * sizeof(float)); + } + */ + + if(frameSize != this->frameSize || nCoefs != this->nCoefs) { + + this->frameSize = frameSize; + this->nCoefs = nCoefs; + + if(this->nCoefs > this->frameSize) { + this->nCoefs = this->frameSize; + } + if(this->nCoefs < 1) { + this->nCoefs = 1; + } + + // resize arrays + this->coefs = (float *)realloc(this->coefs, this->nCoefs * sizeof(float)); + // see rta_lpc : corr and coefs are assumed to be of same size + this->corr = (float *)realloc(this->corr, this->nCoefs * sizeof(float)); + } + + // compute previous framerate from rate, offset and width * size ? -> to be able to output values in Hz ? + // also update dimensions according to nCoefs + return this->propagateStreamAttributes(hasTimeTags, rate, offset, 1, this->nCoefs, NULL, false, 1, 1); + //return this->propagateStreamAttributes(hasTimeTags, rate, offset, width, size, NULL, false, 1, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + int ret; + for(unsigned int i = 0; i < num; i++) + { + if(this->frameSize > 1) { + rta_lpc(this->coefs, this->nCoefs, &(this->error), this->corr, values, this->frameSize); + ret = this->propagateFrames(time, weight, this->coefs, this->nCoefs, 1); + } else { + this->coefs[0] = 0.; + ret = this->propagateFrames(time, weight, this->coefs, 1, 1); + } + if(ret != 0) + return ret; + + values += size; + } + return 0; + + } + +}; + +#endif /* PiPoLpc_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoLpcFormants.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoLpcFormants.h new file mode 100644 index 0000000000000000000000000000000000000000..8c6d0013586640b2d3e088e0959abdf82cc253ea --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoLpcFormants.h @@ -0,0 +1,212 @@ +/** + * @file PiPoLpcFormants.h + * @author Gabriel Meseguer-Brocal + * @date 18.05.2016 + * + * @brief PiPo computing formants from LPC + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PiPoLpcFormants_h +#define PiPoLpcFormants_h + +#include "PiPoSequence.h" +#include "PiPoLpc.h" +#include "bbpr.h" +//#include <lpcformants/rpoly.cpp> +#include <vector> +#include <algorithm> + +using namespace std; + +#define PI 3.14159265 + +class PiPoLpcFormants: public PiPoSequence +{ +private: + class PiPoFormants : public PiPo { + float *outValues; + bool f = false; + + public: + PiPoScalarAttr<int> nForm; + PiPoScalarAttr<bool> bandwidth; + PiPoScalarAttr<int> threshold; // Hz + PiPoScalarAttr<float> sr; + + + PiPoFormants(PiPo::Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + nForm(this, "nForm", "Number Of Formants", true, 1), + bandwidth(this, "bandwidth", "Store the bandwidth", true, true), + threshold(this, "threshold", "Threshold (in Hz) for the Lowest Formants", true, 20), + sr(this, "Samplerate", "Sample rate of the audio", true, 44100){ + + } + + ~PiPoFormants() + { + if (f){ + free(outValues); + } + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + int nForm = this->nForm.get(); + int bandwidth = this->bandwidth.get(); + int cols = 1; + if (bandwidth) + cols = 2; + outValues = (float *)malloc(cols * nForm * sizeof(float)); + f = true; + + /*const char *FormColNames[cols]; + FormColNames[0] = "FromantFrequency"; + if (bandwidth) + FormColNames[1] = "FormantBandwidth";*/ + const char *FormColNames[2]; + FormColNames[0] = "FromantFrequency"; + if (bandwidth) FormColNames[1] = "FormantBandwidth"; + return this->propagateStreamAttributes(hasTimeTags, rate, offset, cols, nForm, FormColNames, 0, 0.0, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + int nForm = this->nForm.get(); + int threshold = this->threshold.get(); + int bandwidth = this->bandwidth.get(); + + float sr = this->sr.get(); + + int cols = 1; + if (bandwidth) + cols = 2; + + int n, numr; + n = size - 1; // polynomio order + + double *a, *x, *wr, *wi, quad[2]; + + a = new double [size]; x = new double [size]; wr = new double [size]; wi = new double [size]; + + for (unsigned int i = 0; i < size; i++) + a[i] = *(values+i); + + + + + quad[0] = 2.71828e-1; + quad[1] = 3.14159e-1; + get_quads(a,n,quad,x); + numr = roots(x,n,wr,wi); // number of roots found + vector<double> frqs; + vector<double> bw; + vector<pair<double, double> > matrix; + for (int i = 0; i < numr; i++) { + if (wi[i] >= 0) { + float tmp = (atan2(wi[i], wr[i]) * sr)/ (2.0*PI); + if (tmp > threshold) { + frqs.push_back( tmp ); + + bw.push_back( (-1./2.)*(sr/(2*PI))* log( sqrt( (wr[i] * wr[i]) + (wi[i] * wi[i]) ) ) ); + + // Something the roots of the poly are not precise enough and give values above the unitary circle. As results the bw is negative (log of the absolute value of a complex vector > 1) + if (bw.back() < 0){ + bw.back() = - bw.back(); + } + matrix.push_back(make_pair(frqs.back(), bw.back())); + } + + } + } + + sort (matrix.begin(), matrix.end()); + + for (int i = 0; i < nForm; i++) { + if (matrix.size() > 0) { + *(outValues + i * cols) = matrix[i].first; + if (cols > 1) { + *(outValues + i * cols + 1) = matrix[i].second; + } + }else{ + *(outValues + i * cols) = 0; + if (cols > 1) { + *(outValues + i * cols + 1) = 0; + } + } + } + + delete[] a; delete[]x; delete[]wr; delete[]wi; + + //(double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + return this->propagateFrames(time, weight, static_cast<PiPoValue *>(outValues), nForm*cols, 1); + } + }; + + + +public: + PiPoLpc lpc; + PiPoFormants formants; + + + PiPoLpcFormants (PiPo::Parent *parent, PiPo *receiver = NULL) + : PiPoSequence(parent), + lpc(parent), formants(parent) + { + this->add(lpc); + this->add(formants); + + this->setReceiver(receiver); + + this->addAttr(this, "nFormants", "Number of formants", &formants.nForm, true); + this->addAttr(this, "threshold", "Threshold (in Hz) for the Lowest Formants", &formants.threshold); + this->addAttr(this, "Bandwidth", "Output or not the bandwidth", &formants.bandwidth); + + this->addAttr(this, "sr", "samplerate of the input signal", &formants.sr); + + lpc.nCoefsA.set(2*formants.nForm.get() + 3); // nCoefsA is two times the expected number of formants + 2 (+1 because the firts coef = 1) + + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + lpc.nCoefsA.set(2*formants.nForm.get() + 3, true); + return PiPoSequence::streamAttributes(hasTimeTags, rate, offset, width, size, labels, hasVarSize, domain, maxFrames); + } +}; + + +#endif /* PiPoLpcFormants_h */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMeanStddev.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMeanStddev.h new file mode 100644 index 0000000000000000000000000000000000000000..5b6618cab59e66a05096d524f58eee9b75a611a6 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMeanStddev.h @@ -0,0 +1,126 @@ +/** + * @file PiPoMeanStddev.h + * @author Norbert.Schnell@ircam.fr + * + * @brief Mean Stddev Min Max PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012 by IMTR IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _PIPO_MEAN_STDDEV_ +#define _PIPO_MEAN_STDDEV_ + +#include "PiPo.h" + +using namespace std; + +class PiPoMeanStddev : public PiPo +{ +private: + float outputFrame[2]; + double sum; + double sumOfSquare; + int num; + +public: + PiPoMeanStddev(PiPo *receiver = NULL) + { + this->sum = 0.0; + this->sumOfSquare = 0.0; + this->num = 0; + + this->receiver = receiver; + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + char *msLabels[2]; + + msLabels[0] = "Mean"; + msLabels[1] = "Stddev"; + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, 2, 1, msLabels, 0, 0.0, 1); + } + + int reset(void) + { + this->sum = 0.0; + this->sumOfSquare = 0.0; + this->num = 0; + + return this->propagateReset(); + }; + + int frames(double time, float *values, unsigned int size, unsigned int num) + { + double norm = 1.0 / size; + + for(int i = 0; i < num; i++) + { + double mean = 0.0; + double meanOfSquare = 0.0; + double squareOfmean; + + for(int j = 0; j < size; j++) + { + double x = values[j]; + + mean += x; + meanOfSquare += x * x; + } + + this->sum += sum; + this->sumOfSquare += meanOfSquare; + this->num++; + + mean *= norm; + meanOfSquare *= norm; + squareOfmean = mean * mean; + + this->outputFrame[0] = mean; + + if(meanOfSquare > squareOfmean) + this->outputFrame[1] = sqrt(meanOfSquare - squareOfmean); + else + this->outputFrame[1] = 0.0; + + int ret = this->propagateFrames(time, this->outputFrame, 2, 1); + + if(ret != 0) + return ret; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMedian.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMedian.h new file mode 100644 index 0000000000000000000000000000000000000000..2047b99e7f022afaa080f93958c24efeef41327c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMedian.h @@ -0,0 +1,215 @@ +/** + * @file PiPoMedian.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo calculating a runnning median on a stream + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_MEDIAN_ +#define _PIPO_MEDIAN_ + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_selection.h" +} + +#include <vector> + +#define RING_ALLOC_BLOCK 256 + +class PiPoMedian : public PiPo +{ + template <class T> + class Ring + { + public: + std::vector<double> time; + std::vector<T> vector; + unsigned int width; + unsigned int capacity; + unsigned int size; + unsigned int index; + + public: + Ring(void) : vector() + { + this->width = 1; + this->capacity = 0; + this->size = 0; + this->index = 0; + }; + + void resize(int width, int size) + { + this->time.resize(size); + this->vector.resize(width * size); + this->width = width; + this->capacity = size; + this->size = 0; + this->index = 0; + }; + + void reset(void) + { + this->size = 0; + this->index = 0; + }; + + int input(double time, T *values, unsigned int num, double &outputTime) + { + float *ringValues = &this->vector[this->index * this->width]; + + this->time[this->index] = time; + + if(num > this->width) + num = this->width; + + /* copy frame */ + memcpy(ringValues, values, num * sizeof(T)); + + /* zero pad this values */ + if(num < this->width) + memset(ringValues + num, 0, (this->width - num) * sizeof(T)); + + this->index++; + + if(this->index >= this->capacity) + { + this->size = this->capacity; + this->index = 0; + } + else if(this->size < this->index) + this->size = this->index; + + if(this->size & 1) + { + int timeIndex = this->index - ((this->size + 1) >> 1); + + if(timeIndex < 0) + timeIndex += this->capacity; + + outputTime = this->time[timeIndex]; + } + else + { + int timeIndexB = this->index - (this->size >> 1) - 1; + int timeIndexA = this->index - (this->size >> 1); + + if(timeIndexB < 0) + timeIndexB += this->capacity; + + if(timeIndexA < 0) + timeIndexA += this->capacity; + + outputTime = 0.5 * (this->time[timeIndexB] + this->time[timeIndexA]); + } + + return this->size; + }; + }; + + Ring<float> buffer; + std::vector<float> temp; + std::vector<float> frame; + unsigned int filterSize; + unsigned int inputSize; + +public: + PiPoScalarAttr<int> size; + + PiPoMedian(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + buffer(), temp(), frame(), + size(this, "size", "Filter Size", true, 7) + { + this->filterSize = 0; + this->inputSize = 0; + } + + ~PiPoMedian(void) + { + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int filterSize = this->size.get(); + unsigned int inputSize = width * size; + double lag = 1000.0 * 0.5 * (filterSize - 1) / rate; + + if(filterSize != this->filterSize || inputSize != this->inputSize) + { + this->buffer.resize(inputSize, filterSize); + this->temp.resize(inputSize * filterSize); + this->frame.resize(inputSize); + this->filterSize = filterSize; + this->inputSize = inputSize; + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset - lag, width, size, labels, 0, 0.0, 1); + } + + int reset(void) + { + this->buffer.reset(); + return this->propagateReset(); + }; + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + for(unsigned int i = 0; i < num; i++) + { + double outputTime; + int filterSize = this->buffer.input(time, values, size, outputTime); + + this->temp = this->buffer.vector; + + for(unsigned int j = 0; j < this->buffer.width; j++) + this->frame[j] = rta_selection_stride(&this->temp[j], this->buffer.width, filterSize, (filterSize - 1) * 0.5); + + int ret = this->propagateFrames(outputTime, weight, &this->frame[0], this->inputSize, 1); + + if(ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMel.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMel.h new file mode 100644 index 0000000000000000000000000000000000000000..be2b279e6508f90441a8f65b6fe55f59aadd783d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMel.h @@ -0,0 +1,75 @@ +/** + * @file PiPoMel.h + * @author Norbert.Schnell@ircam.fr + * + * @brief RTA MEL bands PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_MEL_ +#define _PIPO_MEL_ + +#include "PiPoSlice.h" +#include "PiPoFft.h" +#include "PiPoBands.h" + +class PiPoMel: public PiPoSlice +{ +public: + PiPoFft fft; + PiPoBands bands; + + PiPoMel(Parent *parent, PiPo *receiver = NULL) : + PiPoSlice(parent, &this->fft), + fft(parent, &this->bands), + bands(parent, receiver) + { + /* steal attributes from member PiPos */ + this->addAttr(this, "windsize", "FFT Window Size", &this->size, true); + this->addAttr(this, "hopsize", "FFT Hop Size", &this->hop); + this->addAttr(this, "numbands", "Number Of Bands", &bands.num); + this->addAttr(this, "log", "Logarithmic Scale Output", &bands.log); + + /* set internal attributes */ + this->wind.set(PiPoSlice::BlackmanWindow); + this->norm.set(PiPoSlice::PowerNorm); + this->fft.mode.set(PiPoFft::PowerFft); + this->bands.mode.set(PiPoBands::MelBands); + this->bands.log.set(false); + } + + void setReceiver(PiPo *receiver, bool add) { this->bands.setReceiver(receiver, add); }; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMfcc.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMfcc.h new file mode 100644 index 0000000000000000000000000000000000000000..dcb43bcd0a6fc155a84d80cf0215491971c256da --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMfcc.h @@ -0,0 +1,79 @@ +/** + * @file PiPoMfcc.h + * @author Norbert.Schnell@ircam.fr + * + * @brief RTA MFCC PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_MFCC_ +#define _PIPO_MFCC_ + +#include "PiPoSlice.h" +#include "PiPoFft.h" +#include "PiPoBands.h" +#include "PiPoDct.h" + +class PiPoMfcc : public PiPoSlice +{ +public: + PiPoFft fft; + PiPoBands bands; + PiPoDct dct; + + PiPoMfcc(Parent *parent, PiPo *receiver = NULL) : + PiPoSlice(parent, &this->fft), + fft(parent, &this->bands), + bands(parent, &this->dct), + dct(parent, receiver) + { + /* steal attributes from member PiPos */ + this->addAttr(this, "windsize", "FFT Window Size", &this->size, true); + this->addAttr(this, "hopsize", "FFT Hop Size", &this->hop); + this->addAttr(this, "numbands", "Number Of Bands", &bands.num); + this->addAttr(this, "numcoeffs", "Number Of MFC Coefficients", &dct.order); + + /* set internal attributes */ + this->wind.set(PiPoSlice::BlackmanWindow); + this->norm.set(PiPoSlice::PowerNorm); + this->fft.mode.set(PiPoFft::PowerFft); + this->bands.mode.set(PiPoBands::MelBands); + this->bands.log.set(true); + this->dct.order.set(12); + } + + void setReceiver(PiPo *receiver, bool add) { this->dct.setReceiver(receiver, add); }; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMinMax.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMinMax.h new file mode 100644 index 0000000000000000000000000000000000000000..f39b53759d1df5803ab67f807584a3de92cb4287 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMinMax.h @@ -0,0 +1,115 @@ +/** + * @file PiPoMinMax.h + * @author Norbert.Schnell@ircam.fr + * + * @brief Mean Stddev Min Max PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012 by IMTR IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_MIN_MAX_ +#define _PIPO_MIN_MAX_ + +#include "PiPo.h" + +class PiPoMinMax : public PiPo +{ +private: + float outputFrame[2]; + double min; + double max; + +public: + PiPoMinMax(PiPo *receiver = NULL) + { + this->min = DBL_MAX; + this->max = -DBL_MAX; + this->receiver = receiver; + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + const char *mmLabels[2]; + + mmLabels[0] = "Min"; + mmLabels[1] = "Max"; + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, 2, 1, mmLabels, 0, 0.0, 1); + } + + int reset(void) + { + this->min = DBL_MAX; + this->max = -DBL_MAX; + + return this->propagateReset(); + }; + + int frames(double time, float *values, unsigned int size, unsigned int num) + { + for(unsigned int i = 0; i < num; i++) + { + double min = values[0]; + double max = min; + + for(unsigned int j = 0; j < size; j++) + { + double x = values[j]; + + if(x < min) + min = x; + + if(x > max) + max = x; + } + + if(min < this->min) + this->min = min; + + if(max < this->max) + this->max = max; + + this->outputFrame[0] = min; + this->outputFrame[1] = max; + + int ret = this->propagateFrames(time, this->outputFrame, 2, 1); + + if(ret != 0) + return ret; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMoments.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMoments.h new file mode 100644 index 0000000000000000000000000000000000000000..57f061fb56cf877572468bbe573c88ab19aa1325 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMoments.h @@ -0,0 +1,240 @@ +/** + * @file PiPoMoments.h + * @author jules.francoise@ircam.fr + * + * @brief PiPo calculating the moments of a vector + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef maxpipo_PiPoMoments_h +#define maxpipo_PiPoMoments_h + +#define MAX_PIPO_MOMENTS_LABELS 128 + +#ifdef WIN32 +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#include "PiPo.h" +#include <cmath> + +extern "C" { +#include "rta_configuration.h" +#include "rta_moments.h" +} + +using namespace std; + +class PiPoMoments : public PiPo +{ +protected: + vector<float> moments; + double domain; +public: + enum OutputScaling { None, Domain, Normalized }; + PiPoScalarAttr<int> order; + PiPoScalarAttr<PiPo::Enumerate> scaling; + PiPoScalarAttr<bool> std; + + PiPoMoments(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + order(this, "order", "Maximum order of moments", true, 4), + scaling(this, "scaling", "Output Scaling", true, None), + std(this, "std", "Standardized moments for order > 2", true, true) + { + this->scaling.addEnumItem("None", "No Scaling (bins)"); + this->scaling.addEnumItem("Domain", "Domain Scaling"); + this->scaling.addEnumItem("Normalized", "Normalized Moments"); + } + + ~PiPoMoments(void) + { + this->moments.clear(); + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + this->domain = domain; + unsigned int maxorder = (unsigned int)this->order.get(); + this->moments.resize(maxorder); + + const char *momentsColNames[MAX_PIPO_MOMENTS_LABELS]; + // Set 4 first moments names + momentsColNames[0] = "Centroid"; + momentsColNames[1] = "Spread"; + momentsColNames[2] = "Skewness"; + momentsColNames[3] = "Kurtosis"; + + unsigned int maxlabel = min((int)maxorder, MAX_PIPO_MOMENTS_LABELS); + for (unsigned int ord=4; ord<maxlabel; ord++) { + momentsColNames[ord] = ""; + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, maxorder, 1, momentsColNames, 0, 0.0, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + float input_sum; + unsigned int maxorder = (unsigned int)this->order.get(); + rta_real_t deviation; + + for(unsigned int i = 0; i < num; i++) + { + if (maxorder >= 1) { + this->moments[0] = rta_weighted_moment_1_indexes(&input_sum, + values, + size); + + if (maxorder >= 2) { + if (input_sum != 0.) { + this->moments[1] = rta_weighted_moment_2_indexes(values, + size, + this->moments[0], + input_sum); + } else { + this->moments[1] = size; + } + + if (maxorder >= 3) { + if (this->std.get()) { // Standardized + deviation = sqrtf(this->moments[1]); + if (input_sum != 0. && deviation != 0.) { + this->moments[2] = rta_std_weighted_moment_3_indexes(values, + size, + this->moments[0], + input_sum, + deviation); + } else { + this->moments[2] = 0.; + } + } else { // Not Standardized + if (input_sum != 0.) { + this->moments[2] = rta_weighted_moment_3_indexes(values, + size, + this->moments[0], + input_sum); + } else { + this->moments[2] = 0.; + } + } + + if (maxorder >= 4) { + if (this->std.get()) { // Standardized + if (input_sum != 0. && deviation != 0.) { + this->moments[3] = rta_std_weighted_moment_4_indexes(values, + size, + this->moments[0], + input_sum, + deviation); + } else { + this->moments[3] = 2.; + } + } else { // Not Standardized + if (input_sum != 0.) { + this->moments[3] = rta_weighted_moment_4_indexes(values, + size, + this->moments[0], + input_sum); + } else { + this->moments[3] = 0.; + } + + } + + for (unsigned int ord=5; ord<=maxorder; ord++) { + if (this->std.get()) { // Standardized + if (input_sum != 0. && deviation != 0.) { + this->moments[ord-1] = rta_std_weighted_moment_indexes(values, + size, + this->moments[0], + input_sum, + deviation, + (rta_real_t)ord); + } else { + if(ord & 1) /* even */ + { + this->moments[ord-1] = 0.; + } + else + { + this->moments[ord-1] = ord; + } + } + } else { // Not Standardized + if (input_sum != 0.) { + this->moments[ord-1] = rta_weighted_moment_indexes(values, + size, + this->moments[0], + input_sum, + (rta_real_t)ord); + } else { + this->moments[ord-1] = size; + } + } + } + } + } + } + } + + enum OutputScaling outputScaling = (enum OutputScaling)this->scaling.get(); + switch (outputScaling) { + case None: + break; + case Domain: + for (unsigned int ord=0; ord<2; ord++) { + this->moments[ord] *= powf(float(domain / (size-1)), float(ord+1)); + } + break; + case Normalized: + for (unsigned int ord=0; ord<maxorder; ord++) { + this->moments[ord] /= powf(float(size-1), float(ord+1)); + } + break; + } + + int ret = this->propagateFrames(time, weight, &moments[0], maxorder, 1); + + if(ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMvavrg.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMvavrg.h new file mode 100644 index 0000000000000000000000000000000000000000..86b7de11cb1287259c5d5ef6d3e1368f1675cbf2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoMvavrg.h @@ -0,0 +1,211 @@ +/** + * @file PiPoMvavrg.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo calculating a moving average on a stream + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_MVAVRG_ +#define _PIPO_MVAVRG_ + +#include "PiPo.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_mean_variance.h" +} + +#include <vector> + +#define RING_ALLOC_BLOCK 256 + +class PiPoMvavrg : public PiPo +{ + template <class T> + class Ring + { + public: + std::vector<double> time; + std::vector<T> vector; + unsigned int width; + unsigned int capacity; + unsigned int size; + unsigned int index; + + public: + Ring(void) : vector() + { + this->width = 1; + this->capacity = 0; + this->size = 0; + this->index = 0; + }; + + void resize(int width, int size) + { + this->time.resize(size); + this->vector.resize(width * size); + this->width = width; + this->capacity = size; + this->size = 0; + this->index = 0; + }; + + void reset(void) + { + this->size = 0; + this->index = 0; + }; + + int input(double time, T *values, unsigned int num, double &outputTime) + { + float *ringValues = &this->vector[this->index * this->width]; + + this->time[this->index] = time; + + if(num > this->width) + num = this->width; + + /* copy frame */ + memcpy(ringValues, values, num * sizeof(T)); + + /* zero pad this values */ + if(num < this->width) + memset(ringValues + num, 0, (this->width - num) * sizeof(T)); + + this->index++; + + if(this->index >= this->capacity) + { + this->size = this->capacity; + this->index = 0; + } + else if(this->size < this->index) + this->size = this->index; + + if(this->size & 1) + { + int timeIndex = this->index - ((this->size + 1) >> 1); + + if(timeIndex < 0) + timeIndex += this->capacity; + + outputTime = this->time[timeIndex]; + } + else + { + int timeIndexB = this->index - (this->size >> 1) - 1; + int timeIndexA = this->index - (this->size >> 1); + + if(timeIndexB < 0) + timeIndexB += this->capacity; + + if(timeIndexA < 0) + timeIndexA += this->capacity; + + outputTime = 0.5 * (this->time[timeIndexB] + this->time[timeIndexA]); + } + + return this->size; + }; + }; + + Ring<float> buffer; + std::vector<float> frame; + unsigned int filterSize; + unsigned int inputSize; + +public: + PiPoScalarAttr<int> size; + + PiPoMvavrg(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + buffer(), frame(), + size(this, "size", "Filter Size", true, 8) + { + this->filterSize = 0; + this->inputSize = 0; + }; + + ~PiPoMvavrg(void) + { + }; + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int filterSize = this->size.get(); + unsigned int inputSize = width * size; + double lag = 1000.0 * 0.5 * (filterSize - 1) / rate; + + if(filterSize != this->filterSize || inputSize != this->inputSize) + { + this->buffer.resize(inputSize, filterSize); + this->frame.resize(inputSize); + this->filterSize = filterSize; + this->inputSize = inputSize; + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset - lag, width, size, labels, 0, 0.0, 1); + }; + + int reset(void) + { + this->buffer.reset(); + return this->propagateReset(); + }; + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + for(unsigned int i = 0; i < num; i++) + { + double outputTime; + int filterSize = this->buffer.input(time, values, size, outputTime); + + for(unsigned int j = 0; j < this->buffer.width; j++) + this->frame[j] = rta_mean_stride(&this->buffer.vector[j], this->buffer.width, filterSize); + + int ret = this->propagateFrames(outputTime, weight, &this->frame[0], this->inputSize, 1); + + if(ret != 0) + return ret; + + values += size; + } + + return 0; + }; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoOnseg.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoOnseg.h new file mode 100644 index 0000000000000000000000000000000000000000..2290d865b6dd904ed7e4eebcbeb733f220ad65eb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoOnseg.h @@ -0,0 +1,451 @@ +/** + * @file PiPoOnseg.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo calculating a runnning median on a stream + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_ODFSEG_ +#define _PIPO_ODFSEG_ + +#include "PiPo.h" +#include "RingBuffer.h" + +extern "C" { +#include "rta_configuration.h" +#include "rta_selection.h" +} + +#include "TempMod.h" +#include <vector> +#include <string> + +class PiPoOnseg : public PiPo +{ +public: + enum OnsetMode { MeanOnset, MeanSquareOnset, RootMeanSquareOnset, KullbackLeiblerOnset }; + +private: + RingBuffer<PiPoValue> buffer; + std::vector<PiPoValue> temp; + std::vector<PiPoValue> frame; + std::vector<PiPoValue> lastFrame; + unsigned int filterSize; + unsigned int inputSize; + double offset; + double frameperiod; + enum OnsetMode onsetMode; + int segmentFrames; //TBD: unused? + bool lastFrameWasOnset; + double onsetTime; + bool enDuration; + bool segIsOn; + TempModArray tempMod; + std::vector<PiPoValue>outputValues; + +public: + PiPoScalarAttr<int> colindex; + PiPoScalarAttr<int> numcols; + PiPoScalarAttr<int> fltsize; + PiPoScalarAttr<double> threshold; + PiPoScalarAttr<PiPo::Enumerate> onsetmode; + PiPoScalarAttr<double> mininter; + PiPoScalarAttr<bool> startisonset; + PiPoScalarAttr<bool> duration; + PiPoScalarAttr<double> durthresh; + PiPoScalarAttr<double> offthresh; + PiPoScalarAttr<double> maxsegsize; + PiPoScalarAttr<bool> enMin; + PiPoScalarAttr<bool> enMax; + PiPoScalarAttr<bool> enMean; + PiPoScalarAttr<bool> enStddev; + PiPoScalarAttr<bool> odfoutput; + + PiPoOnseg(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + buffer(), temp(), frame(), lastFrame(), tempMod(), outputValues(), + colindex(this, "colindex", "Index of First Column Used for Onset Calculation", true, 0), + numcols(this, "numcols", "Number of Columns Used for Onset Calculation", true, -1), + fltsize(this, "filtersize", "Filter Size", true, 3), + threshold(this, "threshold", "Onset Threshold", false, 5), + onsetmode(this, "odfmode", "Onset Detection Calculation Mode", true, MeanOnset), + mininter(this, "mininter", "Minimum Onset Interval", false, 50.0), + startisonset(this, "startisonset", "Place Marker at Start of Buffer", false, false), + duration(this, "duration", "Output Segment Duration", true, false), + durthresh(this, "durthresh", "Duration Threshold", false, 0.0), + offthresh(this, "offthresh", "Segment End Threshold", false, -80.0), + maxsegsize(this, "maxsize", "Maximum Segment Duration", false, 0.0), + enMin(this, "min", "Calculate Segment Min", true, false), + enMax(this, "max", "Calculate Segment Max", true, false), + enMean(this, "mean", "Calculate Segment Mean", true, false), + enStddev(this, "stddev", "Calculate Segment StdDev", true, false), + odfoutput(this, "odfoutput", "Output only onset detection function", true, false) + { + this->filterSize = 0; + this->inputSize = 0; + + this->offset = 0.0; + this->frameperiod = 1.; + this->onsetMode = MeanOnset; + this->segmentFrames = 0; + this->lastFrameWasOnset = false; + this->onsetTime = -DBL_MAX; + + this->enDuration = false; + this->segIsOn = false; + + this->onsetmode.addEnumItem("mean", "Mean"); + this->onsetmode.addEnumItem("square", "Mean Square"); + this->onsetmode.addEnumItem("rms", "Root Mean Square"); + this->onsetmode.addEnumItem("kullbackleibler", "Kullback Leibler Divergence"); + } + + ~PiPoOnseg(void) + { + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + int filterSize = this->fltsize.get(); + enum OnsetMode onsetMode = (enum OnsetMode)this->onsetmode.get(); + int inputSize = width; + + this->frameperiod = 1000.0 / rate; + this->offset = -this->frameperiod; // offset of negative frame period to include signal just before peak + + if(filterSize < 1) + filterSize = 1; + + this->onsetMode = onsetMode; + + /* resize internal buffers */ + this->buffer.resize(inputSize, filterSize); + this->temp.resize(inputSize * filterSize); + this->frame.resize(inputSize); + this->lastFrame.resize(inputSize); + + this->filterSize = filterSize; + this->inputSize = inputSize; + + if (this->startisonset.get()) + { // start with a segment at 0 + this->lastFrameWasOnset = true; + this->onsetTime = -this->offset; // first marker will be at 0 + this->segIsOn = true; + } + else + { + this->lastFrameWasOnset = false; + this->onsetTime = -DBL_MAX; + } + + this->enDuration = this->duration.get() && !this->odfoutput.get(); + + if(this->enDuration) + { + /* resize temporal models */ + this->tempMod.resize(inputSize); + + /* enable temporal models */ + this->tempMod.enable(this->enMin.get(), this->enMax.get(), this->enMean.get(), this->enStddev.get()); + + /* get output size */ + unsigned int outputSize = this->tempMod.getNumValues(); + + /* alloc output vector for duration and temporal modelling output */ + this->outputValues.resize(outputSize + 1); + + /* get labels */ + char *mem = new char[outputSize * 64 + 64]; + char **outLabels = new char*[outputSize + 1]; + + for(unsigned int i = 0; i <= outputSize; i++) + outLabels[i] = mem + i * 64; + + snprintf(outLabels[0], 64, "Duration"); + this->tempMod.getLabels(labels, inputSize, &outLabels[1], 64, outputSize); + + int ret = this->propagateStreamAttributes(true, rate, 0.0, outputSize + 1, 1, (const char **)&outLabels[0], false, 0.0, 1); + + delete [] mem; + delete [] outLabels; + + return ret; + } + + if (this->odfoutput.get()) + { + const char *outlab[1] = { "ODF" }; + return this->propagateStreamAttributes(true, rate, 0.0, 1, 1, outlab, false, 0.0, 1); + } + else + return this->propagateStreamAttributes(true, rate, 0.0, 0, 0, NULL, false, 0.0, 1); + } + + int reset(void) + { + this->buffer.reset(); + + this->segmentFrames = 0; + + if (this->startisonset.get()) + { // start with a segment at 0 + this->lastFrameWasOnset = true; + this->onsetTime = -this->offset; + this->segIsOn = true; + } + else + { + this->lastFrameWasOnset = false; + this->onsetTime = -DBL_MAX; + this->segIsOn = false; + } + + this->tempMod.reset(); + + return this->propagateReset(); + }; + + int frames(double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { + double onsetThreshold = this->threshold.get(); + double minimumInterval = this->mininter.get(); + double durationThreshold = this->durthresh.get(); + double offThreshold = this->offthresh.get(); + int colindex = this->colindex.get(); + int numcols = this->numcols.get(); + //printf("frames at %f size %d num %d\n", time, size, num); + + if(size > this->buffer.width) + size = this->buffer.width; //FIXME: values += size at the end of the loop can be wrong + + // clip colindex/size + //TODO: this shouldn't change at runtime, so do this in streamAttributes only + while (colindex < 0 && size > 0) + colindex += size; + + if (numcols <= 0) + numcols = size; + + if (colindex + numcols > size) + numcols = size - colindex; + + for(unsigned int i = 0; i < num; i++) + { // for all frames + PiPoValue scale = 1.0; + double odf = 0.0; + double energy = 0.0; + + /* normalize sum to one for Kullback Leibler divergence */ + if(this->onsetMode == KullbackLeiblerOnset) + { + PiPoValue normSum = 0.0; + + for(int j = 0; j < numcols; j++) + normSum += values[colindex + j]; + + scale = 1.0 / normSum; + } + + /* input frame */ + int filterSize = this->buffer.input(values, size, scale); + this->temp = this->buffer.vector; + + switch(this->onsetMode) + { + case MeanOnset: + { + unsigned int k = colindex; + for(int j = 0; j < numcols; j++, k++) + { + odf += (values[k] - this->lastFrame[k]); + energy += values[k]; + + this->lastFrame[k] = rta_selection_stride(&this->temp[k], size, filterSize, (filterSize - 1) * 0.5); + } + + odf /= numcols; + energy /= numcols; + + break; + } + + case MeanSquareOnset: + case RootMeanSquareOnset: + { + unsigned int k = colindex; + for(int j = 0; j < numcols; j++, k++) + { + double diff = values[k] - this->lastFrame[k]; + + odf += (diff * diff); + energy += values[k] * values[k]; + + this->lastFrame[k] = rta_selection_stride(&this->temp[k], size, filterSize, (filterSize - 1) * 0.5); + } + + odf /= numcols; + energy /= numcols; + + if(this->onsetMode == RootMeanSquareOnset) + { + odf = sqrt(odf); + energy = sqrt(energy); + } + + break; + } + + case KullbackLeiblerOnset: + { + unsigned int k = colindex; + for(int j = 0; j < numcols; j++, k++) + { + if(values[k] != 0.0 && this->lastFrame[k] != 0.0) + odf += log(this->lastFrame[k] / values[k]) * this->lastFrame[k]; + + energy += values[k] * values[k]; + + this->lastFrame[k] = rta_selection_stride(&this->temp[k], size, filterSize, (filterSize - 1) * 0.5); + } + + odf /= numcols; + energy /= numcols; + + break; + } + } + + /* get onset */ + double maxsize = maxsegsize.get(); + bool frameIsOnset = (odf > onsetThreshold && !this->lastFrameWasOnset && time >= this->onsetTime + minimumInterval) + || (maxsize > 0 && (time >= this->onsetTime + maxsize)); // chop unconditionally after maxsize if given + int ret = 0; + + if(!this->enDuration) + { + if (!this->odfoutput.get()) + { /* output marker */ + if(frameIsOnset) + { + /* report immediate onset */ + ret = this->propagateFrames(this->offset + time, weight, NULL, 0, 1); + this->onsetTime = time; + } + } + else + { /* output odf for each frame*/ + PiPoValue odfval = odf; + ret = this->propagateFrames(this->offset + time, weight, &odfval, 1, 1); + } + } + else + { + double duration = time - this->onsetTime; + + if(this->segIsOn && (frameIsOnset || energy < offThreshold) && duration >= durationThreshold) + { + /* end of segment (new onset or energy below off threshold) */ + int outputSize = static_cast<int>(this->outputValues.size()); + + this->outputValues[0] = duration; + + /* get temporal modelling */ + if(outputSize > 1) + this->tempMod.getValues(&this->outputValues[1], outputSize - 1, true); + + /* report segment */ + ret = this->propagateFrames(this->offset + this->onsetTime, weight, &this->outputValues[0], outputSize, 1); + } + + /* segment on/off (segment has at least one frame) */ + if(frameIsOnset) + { + this->segIsOn = true; + this->onsetTime = time; + } + else if(energy < offThreshold) + this->segIsOn = false; + + /* feed temporal modelling */ + if(this->segIsOn) + this->tempMod.input(values, size); + } + + this->lastFrameWasOnset = frameIsOnset; + + if(ret != 0) + return ret; + + values += size; + time += this->frameperiod; // increase time for next input frame (if num > 1) + } // end for all frames + + return 0; + } + + int finalize(double inputEnd) + { + double durationThreshold = this->durthresh.get(); + double duration = inputEnd - this->onsetTime; + //printf("finalize at %f seg %d duration %f\n", inputEnd, segIsOn, duration); + + if(this->segIsOn && duration >= durationThreshold) + { + /* end of segment (new onset or below off threshold) */ + int outputSize = static_cast<int>(this->outputValues.size()); + + this->outputValues[0] = duration; + + /* get temporal modelling */ + if(outputSize > 1) + this->tempMod.getValues(&this->outputValues[1], outputSize - 1, true); + + /* report segment */ + return this->propagateFrames(this->offset + this->onsetTime, 0.0, &this->outputValues[0], outputSize, 1); + } + + return this->propagateFinalize(inputEnd); + } +}; + +/** EMACS ** + * Local variables: + * mode: c++ + * c-basic-offset:2 + * End: + */ + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoPeaks.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoPeaks.h new file mode 100644 index 0000000000000000000000000000000000000000..2a3dcc5271ee81015b36987ebd02554f7531ce7b --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoPeaks.h @@ -0,0 +1,284 @@ +/** + * @file PiPoPeaks.h + * + * @brief PiPo estimating local maxima of a vector + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2013-2017 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_PEAKS_ +#define _PIPO_PEAKS_ + +#include "PiPo.h" + +extern "C" { +#include <math.h> +} + +#include <cstdlib> + +#define PIPO_PEAKS_DEBUG 1 +#define ABS_MAX 2147483647.0 +#define DEFAULT_NUM_ALLOC_PEAKS 200 + +typedef struct +{ + float freq; + float amp; +} peak_t; + +static int +peaks_compare_freq(const void *left, const void *right) +{ + peak_t *l = (peak_t *)left; + peak_t *r = (peak_t *)right; + + return (r->freq < l->freq) - (l->freq < r->freq); +} + +static int +peaks_compare_amp(const void *left, const void *right) +{ + peak_t *l = (peak_t *)left; + peak_t *r = (peak_t *)right; + + return (r->amp > l->amp) - (l->amp > r->amp); +} + +class PiPoPeaks : public PiPo +{ +private: + std::vector<float> buffer_; + int domsr; + double peaksRate; + int allocatedPeaksSize; + +public: + PiPoScalarAttr<int> numPeaks; + PiPoScalarAttr<PiPo::Enumerate> keepMode; + PiPoScalarAttr<PiPo::Enumerate> downSampling; + PiPoScalarAttr<double> thresholdWidth; + PiPoScalarAttr<double> thresholdHeight; + PiPoScalarAttr<double> thresholdDev; + PiPoScalarAttr<double> rangeLow; + PiPoScalarAttr<double> rangeHigh; + PiPoScalarAttr<double> domainScale; + + // constructor + PiPoPeaks (Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), buffer_(), + numPeaks(this, "numpeaks", "Maximum number of peaks to be estimated", true, 16), + keepMode(this, "keep", "keep first or strongest peaks", true, 0), + downSampling(this, "downsampling", "Downsampling Exponent", true, 2), + thresholdWidth(this, "thwidth", "maximum width for peaks (indicates sinusoidality)", true, 0.), + thresholdHeight(this, "thheight", "minimum height for peaks", true, 0.), + thresholdDev(this, "thdev", "maximum deviation from mean value", true, 0.), + rangeLow(this, "rangelow", "minimun of band where to search for peaks", true, 0.), + rangeHigh(this, "rangehigh", "maximum of band where to search for peaks", true, ABS_MAX), + domainScale(this, "domscale", "scaling factor of output peaks (overwrites domain and down)", true, -0.5) + { + + this->keepMode.addEnumItem("strongest", "keep strongest peak"); + this->keepMode.addEnumItem("lowest", "keep first peak"); + + this->downSampling.addEnumItem("none", "No down sampling"); + this->downSampling.addEnumItem("2x", "Down sampling by 2"); + this->downSampling.addEnumItem("4x", "Down sampling by 4"); + this->downSampling.addEnumItem("8x", "Down sampling by 8"); + + this->domsr = 1; + this->allocatedPeaksSize = 0; + } + + ~PiPoPeaks (void) + { + } + + int streamAttributes (bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { +#if PIPO_PEAKS_DEBUG + printf("PiPoPeaks %p streamAttributes timetags %d rate %f offset %f width %d height %d labels %s varsize %d domain %f maxframes %d\n", + this, hasTimeTags, rate, offset, width, height, labels ? labels[0] : "n/a", hasVarSize, domain, maxFrames); +#endif + + int maxNumPeaks = this->numPeaks.get(); + this->peaksRate = rate; + + const char *peaksColNames[2]; + peaksColNames[0] = "Frequency"; + peaksColNames[1] = "Amplitude"; + + this->allocatedPeaksSize = maxNumPeaks; + if(this->allocatedPeaksSize < DEFAULT_NUM_ALLOC_PEAKS) this->allocatedPeaksSize = DEFAULT_NUM_ALLOC_PEAKS; + this->buffer_.resize(this->allocatedPeaksSize * 2); + + return this->propagateStreamAttributes(true, rate, offset, 2, maxNumPeaks, peaksColNames, 1, 0.0, 1); + } + + int reset (void) + { + return this->propagateReset(); + } + + + int frames (double time, double weight, float *values, unsigned int size, unsigned int num) + { + float *peaks_ptr = &this->buffer_[0]; + int n_found = 0; + double mean = -ABS_MAX; + unsigned int start, end; + unsigned int i, j; + double thresholdDev = this->thresholdDev.get(); + double thresholdHeight = this->thresholdHeight.get(); + double thresholdWidth = this->thresholdWidth.get(); + int maxNumPeaks = this->numPeaks.get(); + double domscale = this->domainScale.get(); + + if(this->domsr != 0) + domscale *= this->peaksRate; + + if(domscale < 0.0) + domscale = -domscale / (double)size; + + start = (unsigned int)floor(this->rangeLow.get() / domscale); + end = (unsigned int)ceil(this->rangeHigh.get() / domscale); + + if(start < 1) + start = 1; + + if(end >= size) + end = size - 1; + + if(thresholdDev > 0.0) + { + mean = 0.0; + + for(i=0, j=0; i < size; i++, j++) + mean += values[j]; + + mean /= size; + } + + for(i = start, j = start; i < end; i++, j++) + { + double center = values[j]; + double left = values[j - 1]; + double right = values[j + 1]; + + if(center >= left && center > right) + { + double a = 0.5 * (right + left) - center; + double b = 0.5 * (right - left); + double frac = -b / (2.0 * a); + double max_amp = (a * frac + b) * frac + center; + double max_index = (double)i + frac; + + if(fabs(max_amp - mean) < thresholdDev) + continue; + + if(thresholdHeight > 0.0 || thresholdWidth > 0.0) + { + double min_right_amp = center; + double min_left_amp = center; + double min_right_index = size; + double min_left_index = 0; + unsigned int k, l; + + thresholdWidth = thresholdWidth / domscale; + + for(k=i+1, l=j+1; k<size-1; k++, l++) + { + if(values[l] <= values[l + 1]) + { + left = values[l - 1]; + center = values[l]; + right = values[l + 1]; + + a = 0.5 * (right + left) - center; + b = 0.5 * (right - left); + frac = -b / (2.0 * a); + min_right_amp = (a * frac + b) * frac + center; + min_right_index = (double)k + frac; + + break; + } + } + + for(k=i-1, l=j-1; k>0; k--, l-=1) + { + if(values[l] <= values[l - 1]) + { + left = values[l - 1]; + center = values[l]; + right = values[l + 1]; + + a = 0.5 * (right + left) - center; + b = 0.5 * (right - left); + frac = -b / (2.0 * a); + min_left_amp = (a * frac + b) * frac + center; + min_left_index = (double)k + frac; + + break; + } + } + + if(max_amp - min_right_amp < thresholdHeight || max_amp - min_left_amp < thresholdHeight) + continue; + + if(min_right_index - min_left_index < thresholdWidth) + continue; + } + + peaks_ptr[2 * n_found] = max_index * domscale; + peaks_ptr[2 * n_found + 1] = max_amp; + n_found++; + + if((this->keepMode.get() == 0 && n_found >= maxNumPeaks) || (this->keepMode.get() == 1 && n_found >= this->allocatedPeaksSize)) + break; + } + } + + if(this->keepMode.get() == 0)// keep strongest + { + qsort((void *)peaks_ptr, n_found, sizeof(peak_t), peaks_compare_amp); + + if(n_found > this->numPeaks.get()) + n_found = maxNumPeaks; + + qsort((void *)peaks_ptr, n_found, sizeof(peak_t), peaks_compare_freq); + } + return propagateFrames(time, 1.0, peaks_ptr, 2*n_found, 1); + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoRms.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoRms.h new file mode 100644 index 0000000000000000000000000000000000000000..ccfbd2ec635b1d30cbf926e0dad9f812b1bafa2e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoRms.h @@ -0,0 +1,111 @@ +/** + * @file PiPoRms.h + * @author Norbert.Schnell@ircam.fr + * + * @brief Mean Stddev Min Max PiPo + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012 by IMTR IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_RMS_ +#define _PIPO_RMS_ + +#include "PiPo.h" + +using namespace std; + +class PiPoRms : public PiPo +{ +private: + float outputFrame[2]; + double sumOfSquare; + int num; + +public: + PiPoRms(PiPo *receiver = NULL) + { + this->sumOfSquare = 0.0; + this->num = 0; + + this->receiver = receiver; + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + char *rmsLabels[1]; + + rmsLabels[0] = "Rms"; + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, 1, 1, rmsLabels, 0, 0.0, 1); + } + + int reset(void) + { + this->sumOfSquare = 0.0; + this->num = 0; + + return this->propagateReset(); + }; + + int frames(double time, float *values, unsigned int size, unsigned int num) + { + double norm = 1.0 / size; + + for(int i = 0; i < num; i++) + { + double meanOfSquare = 0.0; + + for(int j = 0; j < size; j++) + { + double x = values[j]; + meanOfSquare += x * x; + } + + this->sumOfSquare += meanOfSquare; + this->num += num; + + meanOfSquare *= norm; + + this->outputFrame[0] = meanOfSquare; + + int ret = this->propagateFrames(time, this->outputFrame, 2, 1); + + if(ret != 0) + return ret; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoScale.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoScale.h new file mode 100644 index 0000000000000000000000000000000000000000..522de6432485f4c4c2f6a4d527082b026baf8d3e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoScale.h @@ -0,0 +1,420 @@ +/** + * @file PiPoScale.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo scale data stream + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_SCALE_ +#define _PIPO_SCALE_ + +#include "PiPo.h" + +#include <math.h> +#include <vector> + +#define defMinLogVal 1e-24f + +class PiPoScale : public PiPo +{ +public: + enum ScaleFun { ScaleLin, ScaleLog, ScaleExp }; + enum CompleteMode { CompleteNot, CompleteRepeatLast, CompleteRepeatAll }; + //static const double defMinLogVal = 1e-24f; + +private: + std::vector<double> extInMin; + std::vector<double> extInMax; + std::vector<double> extOutMin; + std::vector<double> extOutMax; + std::vector<double> inScale; + std::vector<double> inOffset; + std::vector<double> outScale; + std::vector<double> outOffset; + std::vector<float> buffer; + unsigned int frameSize; + enum ScaleFun scaleFunc; + double funcBase; + double minLogVal; + int elemOffset; + int numElems; + int width; + +public: + PiPoVarSizeAttr<double> inMin; + PiPoVarSizeAttr<double> inMax; + PiPoVarSizeAttr<double> outMin; + PiPoVarSizeAttr<double> outMax; + PiPoScalarAttr<bool> clip; + PiPoScalarAttr<PiPo::Enumerate> func; + PiPoScalarAttr<double> base; + PiPoScalarAttr<double> minlog; + PiPoScalarAttr<PiPo::Enumerate> complete; + PiPoScalarAttr<int> colIndex; + PiPoScalarAttr<int> numCols; + + PiPoScale(Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), inScale(), inOffset(), outScale(), outOffset(), buffer(), + inMin(this, "inmin", "Input Minimum", true), + inMax(this, "inmax", "Input Maximum", true), + outMin(this, "outmin", "Output Minimum", true), + outMax(this, "outmax", "Output Maximum", true), + clip(this, "clip", "Clip Values", false, false), + func(this, "func", "Scaling Function", true, ScaleLin), + base(this, "base", "Scaling Base", true, 1.0), + minlog(this, "minlog", "Minimum Log Value", true, defMinLogVal), + complete(this, "complete", "Complete Min/Max Lists", true, CompleteRepeatLast), + colIndex(this, "colindex", "Index of First Column to Scale (negative values count from end)", true, 0), + numCols(this, "numcols", "Number of Columns to Scale (negative values count from end, 0 means all)", true, 0) + { + this->frameSize = 0; + this->scaleFunc = ScaleLin; + this->funcBase = 1.0; + this->minLogVal = defMinLogVal; + + this->func.addEnumItem("lin", "Linear scaling"); + this->func.addEnumItem("log", "Logarithmic scaling"); + this->func.addEnumItem("exp", "Exponential scaling"); + + this->complete.addEnumItem("zeroone"); + this->complete.addEnumItem("repeatlast"); + this->complete.addEnumItem("repeatall"); + } + +private: + // disable copy constructor and assignment operator + PiPoScale (const PiPoScale &other); + const PiPoScale& operator=(const PiPoScale &other); + +public: + ~PiPoScale(void) + { + } + + void extendVector(PiPoVarSizeAttr<double> &attrVec, std::vector<double> &extVec, unsigned int size, double def, enum CompleteMode mode) + { + unsigned int attrSize = attrVec.getSize(); + unsigned int minSize = size; + + if(minSize > attrSize) + minSize = attrSize; + + extVec.resize(size); + + if(attrSize == 0) + mode = CompleteNot; + + for(unsigned int i = 0; i < minSize; i++) + extVec[i] = attrVec[i]; + + switch(mode) + { + case CompleteNot: + { + for(unsigned int i = minSize; i < size; i++) + extVec[i] = def; + + break; + } + + case CompleteRepeatLast: + { + for(unsigned int i = minSize; i < size; i++) + extVec[i] = attrVec[minSize - 1]; + + break; + } + + case CompleteRepeatAll: + { + for(unsigned int i = minSize; i < size; i++) + extVec[i] = attrVec[i % attrSize]; + } + } + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int frameSize = width * size; + enum ScaleFun scaleFunc = (enum ScaleFun)this->func.get(); + double funcBase = this->base.get(); + double minLogVal = this->minlog.get(); + enum CompleteMode completeMode = (enum CompleteMode)this->complete.get(); + + // check and normalise column choice: + // neg. values count from end, no wraparound + int colIndex = this->colIndex.get(); + int numCols = this->numCols.get(); + + if (colIndex < 0) + { + colIndex += width; + + if (colIndex < 0) + colIndex = 0; + } + else if (colIndex >= (int)width) + colIndex = width - 1; + + if (numCols <= 0) + { + numCols += width; + + if (numCols <= 0) + numCols = width; + } + + if (colIndex + numCols > (int)width) + numCols = width - colIndex; + + this->elemOffset = colIndex; + this->numElems = numCols; + this->width = width; + + extendVector(this->inMin, this->extInMin, frameSize, 0.0, completeMode); + extendVector(this->inMax, this->extInMax, frameSize, 1.0, completeMode); + extendVector(this->outMin, this->extOutMin, frameSize, 0.0, completeMode); + extendVector(this->outMax, this->extOutMax, frameSize, 1.0, completeMode); + + this->inScale.resize(frameSize); + this->inOffset.resize(frameSize); + this->outScale.resize(frameSize); + this->outOffset.resize(frameSize); + + if(scaleFunc <= ScaleLin) + { + scaleFunc = ScaleLin; + funcBase = 1.0; + } + else + { + if(scaleFunc > ScaleExp) + scaleFunc = ScaleExp; + + if(funcBase == 1.0) + scaleFunc = ScaleLin; + } + + if(minLogVal > 0.0) + this->minLogVal = minLogVal; + else + this->minlog.set(this->minLogVal); + + if(funcBase < this->minLogVal) + funcBase = this->minLogVal; + + switch(scaleFunc) + { + case ScaleLin: + { + for(unsigned int i = 0; i < frameSize; i++) + { + this->inScale[i] = ((this->extOutMax[i] - this->extOutMin[i]) / (this->extInMax[i] - this->extInMin[i])); + this->inOffset[i] = (this->extOutMin[i] - this->extInMin[i] * this->inScale[i]); + } + + break; + } + + case ScaleLog: + { + for(unsigned int i = 0; i < frameSize; i++) + { + this->inScale[i] = (funcBase - 1.) / (this->extInMax[i] - this->extInMin[i]); + this->inOffset[i] = 1.0 - this->extInMin[i] * this->inScale[i]; + this->outScale[i] = (this->extOutMax[i] - this->extOutMin[i]) / log(funcBase); + this->outOffset[i] = this->extOutMin[i]; + } + + break; + } + + case ScaleExp: + { + for(unsigned int i = 0; i < frameSize; i++) + { + this->inScale[i] = log(funcBase) / (this->extInMax[i] - this->extInMin[i]); + this->inOffset[i] = -this->extInMin[i] * this->inScale[i]; + this->outScale[i] = (this->extOutMax[i] - this->extOutMin[i]) / (funcBase - 1.0); + this->outOffset[i] = this->extOutMin[i] - this->outScale[i]; + } + + break; + } + } + + this->scaleFunc = scaleFunc; + this->funcBase = funcBase; + + this->frameSize = frameSize; + this->buffer.resize(frameSize * maxFrames); + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, width, size, labels, hasVarSize, domain, maxFrames); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int numframes) + { + float *buffer = &this->buffer[0]; + bool clip = this->clip.get(); + unsigned int numrows = size / this->width; + + if (this->elemOffset > 0 || this->numElems < (int)size) + { /* copy through unscaled values */ + memcpy(buffer, values, numframes * size * sizeof(float)); + } + + if(!clip) + { + switch(this->scaleFunc) + { + case ScaleLin: + for (unsigned int i = 0; i < numframes * numrows; i++) + { + for (unsigned int j = 0, k = this->elemOffset; j < this->numElems; j++, k++) + buffer[k] = values[k] * this->inScale[j] + this->inOffset[j]; + + buffer += this->width; + values += this->width; + } + break; + + case ScaleLog: + for (unsigned int i = 0; i < numframes * numrows; i++) + { + for (unsigned int j = 0, k = this->elemOffset; j < this->numElems; j++, k++) + { + double inVal = values[k] * this->inScale[j] + this->inOffset[j]; + + if(inVal < this->minLogVal) + inVal = this->minLogVal; + + buffer[k] = this->outScale[j] * logf(inVal) + this->outOffset[j]; + } + + buffer += this->width; + values += this->width; + } + break; + + case ScaleExp: + for (unsigned int i = 0; i < numframes * numrows; i++) + { + for (unsigned int j = 0, k = this->elemOffset; j < this->numElems; j++, k++) + buffer[k] = this->outScale[j] * expf(values[k] * this->inScale[j] + this->inOffset[j]) + this->outOffset[j]; + + buffer += this->width; + values += this->width; + } + break; + } + } + else + { /* with clipping on */ + switch(this->scaleFunc) + { + case ScaleLin: + for (unsigned int i = 0; i < numframes * numrows; i++) + { + for (unsigned int j = 0, k = this->elemOffset; j < this->numElems; j++, k++) + { + double f = values[k]; + + if(f <= this->extInMin[j]) + buffer[k] = this->extInMin[j]; + else if(f >= this->extInMax[j]) + buffer[k] = this->extInMax[j]; + else + buffer[k] = f * this->inScale[j] + this->inOffset[j]; + } + + buffer += this->width; + values += this->width; + } + break; + + case ScaleLog: + for (unsigned int i = 0; i < numframes * numrows; i++) + { + for (unsigned int j = 0, k = this->elemOffset; j < this->numElems; j++, k++) + { + double f = values[k]; + + if(f <= this->extInMin[j]) + buffer[k] = this->extInMin[j]; + else if(f >= this->extInMax[j]) + buffer[k] = this->extInMax[j]; + else + buffer[k] = this->outScale[j] * log(values[k] * this->inScale[j] + this->inOffset[j]) + this->outOffset[j]; + } + + buffer += this->width; + values += this->width; + } + break; + + case ScaleExp: + for (unsigned int i = 0; i < numframes * numrows; i++) + { + for (unsigned int j = 0, k = this->elemOffset; j < this->numElems; j++, k++) + { + double f = values[k]; + + if(f <= this->extInMin[j]) + buffer[k] = this->extInMin[j]; + else if(f >= this->extInMax[j]) + buffer[k] = this->extInMax[j]; + else + buffer[k] = this->outScale[j] * exp(values[k] * this->inScale[j] + this->inOffset[j]) + this->outOffset[j]; + } + + buffer += this->width; + values += this->width; + } + break; + } + } + + return this->propagateFrames(time, weight, &this->buffer[0], size, numframes); + } +}; + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSelect.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSelect.h new file mode 100644 index 0000000000000000000000000000000000000000..5c467fd51fa413d9baf122ae14635a44ac22bc3a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSelect.h @@ -0,0 +1,300 @@ +/** + * @file PiPoSel.h + * @author joseph.larralde@ircam.fr + * @date 05.01.2016 + * + * @brief PiPo allowing the selection of a subset of rows or columns + * in the incoming stream. + * If no match is found for any selected colum, all columns are passed through. + * Idem for rows. + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2016 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_SEL_H_ +#define _PIPO_SEL_H_ + +#include "PiPo.h" + +extern "C" +{ +#include <stdlib.h> +} + +class PiPoSelect : public PiPo +{ +private: + std::vector<PiPo::Atom> _colNames; + std::vector<int> _rowIndices; + std::vector<unsigned int> _usefulColIndices; // sorted and validity-checked indices + std::vector<unsigned int> _usefulRowIndices; // sorted and validity-checked indices + + unsigned int lastNum; + + unsigned int frameWidth; + unsigned int frameHeight; + + unsigned int outWidth; + unsigned int outHeight; + + unsigned int outFrameSize; + + PiPoValue *outValues; + +public: + PiPoVarSizeAttr<PiPo::Atom> colNames; + PiPoVarSizeAttr<int> rowIndices; + + PiPoSelect(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + colNames(this, "cols", "List of Names or Indices of Columns to Select", true, 1), + rowIndices(this, "rows", "List of Indices of Rows to Select", true, 1, 0) + { + this->lastNum = 0; + + this->frameWidth = 0; + this->frameHeight = 0; + this->outWidth = 0; + this->outHeight = 0; + this->outFrameSize = 0; + + this->outValues = (PiPoValue *)malloc(0); + } + + ~PiPoSelect() + { + free(this->outValues); + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int height, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int cnSize = this->colNames.getSize(); + unsigned int riSize = this->rowIndices.getSize(); + const char *colNames[128]; + + unsigned int frameWidth = width; + unsigned int frameHeight = height; + + //================== check col names changes + bool colNamesChanged = false; + if(cnSize != this->_colNames.size()) + { + colNamesChanged = true; + } + else + { + for(unsigned int i = 0; i < cnSize; i++) + { + if(this->_colNames[i] != this->colNames[i]) + { + colNamesChanged = true; + break; + } + } + } + + //================== check col indices changes + bool rowIndicesChanged = false; + if(riSize != this->_rowIndices.size()) + { + rowIndicesChanged = true; + } + else + { + for(unsigned int i = 0; i < riSize; i++) + { + if(this->_rowIndices[i] != this->rowIndices[i]) + { + rowIndicesChanged = true; + break; + } + } + } + + //=========== check any change in stream attributes and/or PiPo attributes =========// + + if(colNamesChanged || rowIndicesChanged || frameWidth != this->frameWidth || frameHeight != this->frameHeight) + { + /* + for(unsigned int i = 0; i < this->colNames.size(); i++) + { + printf("%s ", this->colNames[i]); + } + printf("\n"); + //*/ + + //copy new col names + this->_colNames.clear(); + for(unsigned int i = 0; i < cnSize; i++) + { + this->_colNames.push_back(this->colNames[i]); + } + + // copy new row indices + this->_rowIndices.clear(); + for(unsigned int i = 0; i < riSize; i++) + { + this->_rowIndices.push_back(this->rowIndices[i]); + } + + // set new input dimensions + this->frameWidth = frameWidth; + this->frameHeight = frameHeight; + + //============== first deal with col indices ================// + + unsigned int cnt = 0; + this->_usefulColIndices.clear(); + for(unsigned int i = 0; i < cnSize; i++) + { + switch(this->_colNames[i].getType()) + { + case Double: + case Int: + { + int res = this->_colNames[i].getInt(); + if(res >= 0 && (unsigned int)res < this->frameWidth) + { + //add res to the indices of valid columns + this->_usefulColIndices.push_back(res); + cnt++; + } + } + break; + + case String: + { + if(labels != NULL) + { + for(unsigned int j = 0; j < this->frameWidth; j++) + { + if(strcmp(this->_colNames[i].getString(), labels[j]) == 0) + { + this->_usefulColIndices.push_back(j); + cnt++; + } + } + } + } + break; + + default: + break; + } + } + /* + printf("selected cols :"); + for(unsigned int i = 0; i < this->_usefulColIndices.size(); i++) + { + printf(" %d", this->_usefulColIndices[i]); + } + printf("\n"); + //*/ + + if(this->_usefulColIndices.size() == 0) // pass all through + { + // fill with all indices + this->_usefulColIndices.resize(this->frameWidth); + for(unsigned int i = 0; i < this->frameWidth; i++) + { + this->_usefulColIndices[i] = i; + } + } + + this->outWidth = static_cast<unsigned int>(this->_usefulColIndices.size()); + // default sorting is ascending order + //std::sort(this->_usefulColIndices.begin(), this->_usefulColIndices.end()); + + //============== now deal with row indices ================// + + this->_usefulRowIndices.clear(); + for(unsigned int i = 0; i < this->_rowIndices.size(); i++) + { + if(this->_rowIndices[i] < (int)(this->frameHeight) && this->_rowIndices[i] >= 0) { + this->_usefulRowIndices.push_back(this->_rowIndices[i]); + } + } + + if(this->_usefulRowIndices.size() == 0) // pass all through + { + // fill with all indices + this->_usefulRowIndices.resize(this->frameHeight); + for(unsigned int i = 0; i < this->frameHeight; i++) + { + this->_usefulRowIndices[i] = i; + } + } + + this->outHeight = static_cast<unsigned int>(this->_usefulRowIndices.size()); + // default sorting is ascending order + //std::sort(this->_usefulRowIndices.begin(), this->_usefulRowIndices.end()); + + this->outFrameSize = this->outWidth * this->outHeight; + } + + for(unsigned int i = 0; i < this->outWidth; i++) + { + colNames[i] = (labels != NULL ? labels[this->_usefulColIndices[i]] : ""); + } + + return this->propagateStreamAttributes(hasTimeTags, rate, offset, this->outWidth, this->outHeight, (labels != NULL ? colNames : NULL), hasVarSize, domain, maxFrames); + } + + int frames(double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) + { + if(num != this->lastNum) { + this->lastNum = num; + this->outValues = (PiPoValue *)realloc(this->outValues, this->outFrameSize * num * sizeof(PiPoValue)); + } + + for(unsigned int n = 0; n < num; n++) + { + unsigned int cnt = 0; + for(unsigned int i = 0; i < this->outHeight; i++) + { + for(unsigned int j = 0; j < this->outWidth; j++) + { + this->outValues[n * this->outFrameSize + cnt] = values[this->_usefulRowIndices[i] * this->frameWidth + this->_usefulColIndices[j]]; + cnt++; + } + } + + values += size; + } + + return this->propagateFrames(time, weight, this->outValues, this->outFrameSize, num); + } +}; + + +#endif /* _PIPO_SEL_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSlice.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSlice.h new file mode 100644 index 0000000000000000000000000000000000000000..081524b8bfe9b64aa3f934d98eb2bccda4b00d5c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSlice.h @@ -0,0 +1,389 @@ +/** + * @file PiPoSlice.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo slicing data stream into windowed frames + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_SLICE_ +#define _PIPO_SLICE_ + +#include "pipo.h" + +#include <math.h> +#include <vector> + +class PiPoSlice : public PiPo +{ +public: + enum WindowTypeE { UndefinedWindow = -1, NoWindow = 0, HannWindow, HammingWindow, BlackmanWindow, BlackmanHarrisWindow, SineWindow, NumWindows }; + enum NormModeE { UndefinedNorm = -1, NoNorm = 0, LinearNorm, PowerNorm }; + +private: + std::vector<float> buffer; + std::vector<float> frame; + std::vector<float> window; + enum WindowTypeE windowType; + enum NormModeE normMode; + double windScale; + + double frameRate; + int inputIndex; + unsigned int inputStride; + unsigned int inputHop; + +public: + PiPoScalarAttr<int> size; + PiPoScalarAttr<int> hop; + PiPoScalarAttr<PiPo::Enumerate> wind; + PiPoScalarAttr<PiPo::Enumerate> norm; + + PiPoSlice(Parent *parent, PiPo *receiver = NULL) : + PiPo(parent, receiver), + buffer(), frame(), window(), + size(this, "size", "Slice Frame Size", true, 2048), + hop(this, "hop", "Slice Hop Size", true, 512), + wind(this, "wind", "Slice Window Type", true, HannWindow), + norm(this, "norm", "Normalize Slice", true, NoNorm) + { + this->windowType = UndefinedWindow; + this->normMode = UndefinedNorm; + this->windScale = 1.0; + + this->inputIndex = 0; + this->inputStride = 0; + this->inputHop = 0; + + this->wind.addEnumItem("none", "No window"); + this->wind.addEnumItem("hann", "Hann window"); + this->wind.addEnumItem("hamming", "Hamming window"); + this->wind.addEnumItem("blackman", "Blackman window"); + this->wind.addEnumItem("blackmanharris", "Blackman-Harris window"); + this->wind.addEnumItem("sine", "Half sine window"); + + this->norm.addEnumItem("none", "No normalization"); + this->norm.addEnumItem("linear", "Linear normalization"); + this->norm.addEnumItem("power", "Power normalization"); + } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + unsigned int frameSize = this->size.get(); + unsigned int hopSize = this->hop.get(); + enum WindowTypeE windowType = (enum WindowTypeE)this->wind.get(); + enum NormModeE normMode = (enum NormModeE)this->norm.get(); + unsigned int inputStride = width * size; + + if(frameSize < 1) + frameSize = 1; + if(hopSize < 1) + hopSize = 1; + + offset += 500.0 * frameSize / rate; + + this->frameRate = rate; + this->inputStride = inputStride; + this->inputHop = hopSize; + + if(frameSize != this->frame.size()) + { + this->buffer.resize(frameSize); + this->frame.resize(frameSize); + this->window.resize(frameSize); + this->windowType = UndefinedWindow; + this->inputIndex = 0; + } + + if(windowType != this->windowType || normMode != this->normMode) + { + this->windowType = windowType; + + double linNorm, powNorm; + initWindow(&this->window[0], frameSize, windowType, normMode, linNorm, powNorm); + + switch(normMode) + { + default: + case NoNorm: + this->windScale = 1.0; + break; + + case LinearNorm: + this->windScale = linNorm; + break; + + case PowerNorm: + this->windScale = powNorm; + break; + } + } + + return this->propagateStreamAttributes(0, rate / (double)hopSize, offset, 1, frameSize, labels, 0, (double)frameSize / rate, 1); + } + + int reset(void) + { + this->inputIndex = 0; + + return this->propagateReset(); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + int inputIndex = this->inputIndex; + unsigned int outputSize = static_cast<unsigned int>(this->frame.size()); + NormModeE normMode = (enum NormModeE)this->norm.get(); + int frameIndex = 0; + + while(num > 0) + { + if(inputIndex >= 0) + { + unsigned int inputSpace = outputSize - inputIndex; + unsigned int numInput = num; + + if(numInput > inputSpace) + numInput = inputSpace; + + if(size == 1) + memcpy(&this->buffer[inputIndex], values, numInput * sizeof(float)); + else + { + for(unsigned int i = 0, j = 0; i < numInput; i++, j += size) + this->buffer[inputIndex + i] = values[j]; + } + + inputIndex += numInput; + frameIndex += numInput; + + if(inputIndex == (int)outputSize) + { + int halfWindowSize = outputSize / 2; + double frameTime = time + 1000.0 * (double)(frameIndex - halfWindowSize) / this->frameRate; + int ret; + + if(this->windowType > NoWindow) + { + this->frame = this->buffer; + + /* apply window and normalization */ + for(unsigned int i = 0; i < outputSize; i++) + this->frame[i] *= (this->window[i] * this->windScale); + + ret = this->propagateFrames(frameTime, weight, &this->frame[0], outputSize, 1); + } + else if(normMode > NoNorm) + { + this->frame = this->buffer; + + /* apply normalization */ + for(unsigned int i = 0; i < outputSize; i++) + this->frame[i] *= this->windScale; + + ret = this->propagateFrames(frameTime, weight, &this->frame[0], outputSize, 1); + } + else + ret = this->propagateFrames(frameTime, weight, &this->buffer[0], outputSize, 1); + + if(ret != 0) + return ret; + + int overlap = outputSize - this->inputHop; + + if(overlap > 0) + memmove(&this->buffer[0], &this->buffer[this->inputHop], overlap * sizeof(float)); + + inputIndex = overlap; + } + + values += numInput; + num -= numInput; + } + else + { + unsigned int numDiscard = -inputIndex; + + if(numDiscard > num) + numDiscard = num; + + inputIndex += numDiscard; + values += numDiscard; + num -= numDiscard; + } + } + + this->inputIndex = inputIndex; + + return 0; + } + +private: + static void initHannWindow(float *ptr, unsigned int size, double &linNorm, double &powNorm) + { + double linSum = 0.0; + double powSum = 0.0; + + for(unsigned int i = 0; i < size; i++) + { + double phi = 2.0 * M_PI * (double)i / (double)size; + double f = 0.5 - 0.5 * cos(phi); + + ptr[i] = f; + + linSum += f; + powSum += f * f; + } + + linNorm = size / linSum; + powNorm = sqrt(size / powSum); + } + + static void initHammingWindow(float *ptr, unsigned int size, double &linNorm, double &powNorm) + { + double linSum = 0.0; + double powSum = 0.0; + + for(unsigned int i = 0; i < size; i++) + { + double phi = 2.0 * M_PI * (double)i / (double)size; + double f = 0.54 - 0.46 * cos(phi); + + ptr[i] = f; + + linSum += f; + powSum += f * f; + } + + linNorm = size / linSum; + powNorm = sqrt(size / powSum); + } + + static void initBlackmanWindow(float *ptr, unsigned int size, double &linNorm, double &powNorm) + { + double linSum = 0.0; + double powSum = 0.0; + + for(unsigned int i = 0; i < size; i++) + { + double phi = 2.0 * M_PI * (double)i / (double)size; + double f = 0.42 - 0.5 * cos(phi) + 0.08 * cos(2.0 * phi); + + ptr[i] = f; + + linSum += f; + powSum += f * f; + } + + linNorm = size / linSum; + powNorm = sqrt(size / powSum); + } + + static void initBlackmanHarrisWindow(float *ptr, unsigned int size, double &linNorm, double &powNorm) + { + double linSum = 0.0; + double powSum = 0.0; + double a0 = 0.35875; + double a1 = 0.48829; + double a2 = 0.14128; + double a3 = 0.01168; + + for(unsigned int i = 0; i < size; i++) + { + double phi = 2.0 * M_PI * (double)i / (double)size; + double f = a0 - a1 * cos(phi) + a2 * cos(2.0 * phi) - a3 * cos(3.0 * phi); + + ptr[i] = f; + + linSum += f; + powSum += f * f; + } + + linNorm = size / linSum; + powNorm = sqrt(size / powSum); + } + + static void initSineWindow(float *ptr, unsigned int size, double &linNorm, double &powNorm) + { + double linSum = 0.0; + double powSum = 0.0; + + for(unsigned int i = 0; i < size; i++) + { + double phi = M_PI * (double)i / (double)size; + double f = sin(phi); + + ptr[i] = f; + + linSum += f; + powSum += f * f; + } + + linNorm = size / linSum; + powNorm = sqrt(size / powSum); + } + + static void initWindow(float *ptr, unsigned int size, int window, NormModeE normMode, double &linNorm, double &powNorm) + { + switch(window) + { + default: + case PiPoSlice::NoWindow: + linNorm = powNorm = 1.0; + break; + + case PiPoSlice::HannWindow: + initHannWindow(ptr, size, linNorm, powNorm); + break; + + case PiPoSlice::HammingWindow: + return initHammingWindow(ptr, size, linNorm, powNorm); + break; + + case PiPoSlice::BlackmanWindow: + initBlackmanWindow(ptr, size, linNorm, powNorm); + break; + + case PiPoSlice::BlackmanHarrisWindow: + initBlackmanHarrisWindow(ptr, size, linNorm, powNorm); + break; + + case PiPoSlice::SineWindow: + initSineWindow(ptr, size, linNorm, powNorm); + break; + } + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSum.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSum.h new file mode 100644 index 0000000000000000000000000000000000000000..92ad3ae4345f3f26188e71d03086705f95ccce4c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/PiPoSum.h @@ -0,0 +1,99 @@ +/** + * @file PiPoSum.h + * @author Norbert.Schnell@ircam.fr + * + * @brief PiPo sum values of data streams + * + * @ingroup pipomodules + * + * @copyright + * Copyright (C) 2012-2014 by IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PIPO_SUM_ +#define _PIPO_SUM_ + +#include "PiPo.h" + +#include <math.h> +#include <vector> +using namespace std; + +class PiPoSum : public PiPo +{ +private: + bool normSum; + +public: + PiPoScalarAttr<bool> norm; + PiPoScalarAttr<const char *> colname; + + PiPoSum(Parent *parent, PiPo *receiver = NULL) + : PiPo(parent, receiver), + norm(this, "norm", "Normalize Sum With Size", false, false), + colname(this, "colname", "Output Column Name", true, "") + { } + + ~PiPoSum(void) + { } + + int streamAttributes(bool hasTimeTags, double rate, double offset, unsigned int width, unsigned int size, const char **labels, bool hasVarSize, double domain, unsigned int maxFrames) + { + const char *name = colname.get(); + return this->propagateStreamAttributes(hasTimeTags, rate, offset, 1, 1, name ? &name : NULL, 0, 0.0, 1); + } + + int frames(double time, double weight, float *values, unsigned int size, unsigned int num) + { + bool normSum = this->norm.get(); + + for(unsigned int i = 0; i < num; i++) + { + float sum = 0.0; + + for(unsigned int j = 0; j < size; j++) + sum += values[j]; + + if(normSum) + sum /= size; + + int ret = this->propagateFrames(time, weight, &sum, 1, 1); + + if(ret != 0) + return ret; + + values += size; + } + + return 0; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/TempMod.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/TempMod.h new file mode 100644 index 0000000000000000000000000000000000000000..478fa45d751bc7e8164cffca996c0101d9efff7d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/TempMod.h @@ -0,0 +1,303 @@ +/** + * @file TempMod.h + * @author Norbert.Schnell@ircam.fr + * + * @brief Temporal modeling util + * + * @copyright + * Copyright (C) 2013 by IMTR IRCAM – Centre Pompidou, Paris, France. + * All rights reserved. + * + * License (BSD 3-clause) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TEMP_MOD_ +#define _TEMP_MOD_ + +extern "C" { +#include "rta_configuration.h" +#include "rta_selection.h" + +#include <float.h> +#include <math.h> +} + +class TempMod +{ +public: + enum ValueId { Min, Max, Mean, StdDev, NumIds }; + + bool enabled[NumIds]; + + PiPoValue min; + PiPoValue max; + PiPoValue sum; + PiPoValue sumOfSquare; + + unsigned int num; + + TempMod(void) + { + for(unsigned int i = 0; i < NumIds; i++) + this->enabled[i] = false; + + this->min = FLT_MAX; + this->max = -FLT_MAX; + + this->sum = 0.0; /* init sum */ + this->sumOfSquare = 0.0; /* init sum of squares */ + + this->num = 0; + }; + + void enable(enum ValueId valId, bool enable = true) + { + this->enabled[valId] = enable; + } + + void enable(bool minEn, bool maxEn = false, bool meanEn = false, bool stddevEn = false) + { + this->enabled[Min] = minEn; + this->enabled[Max] = maxEn; + this->enabled[Mean] = meanEn; + this->enabled[StdDev] = stddevEn; + } + + void select(enum ValueId valId) + { + for(unsigned int i = 0; i < NumIds; i++) + this->enabled[i] = (i == (unsigned int)valId); + } + + unsigned int getNumValues(void) + { + int numValues = 0; + + for(unsigned int i = 0; i < NumIds; i++) + numValues += this->enabled[i]; + + return numValues; + } + + void reset(void) + { + this->min = FLT_MAX; + this->max = -FLT_MAX; + + this->sum = 0.0; /* init sum */ + this->sumOfSquare = 0.0; /* init sum of squares */ + + this->num = 0; + }; + + void input(PiPoValue value) + { + if(this->enabled[Min] && value < this->min) + this->min = value; + + if(this->enabled[Max] && value > this->max) + this->max = value; + + if(this->enabled[Mean] || this->enabled[StdDev]) + this->sum += value; + + if(this->enabled[StdDev]) + this->sumOfSquare += (value * value); + + this->num++; + }; + + unsigned int getValues(PiPoValue *values, unsigned int numValues, bool reset = false) + { + if(this->num > 0) + { + unsigned int index = 0; + + if(this->enabled[Min] && index < numValues) + values[index++] = this->min; + + if(this->enabled[Max] && index < numValues) + values[index++] = this->max; + + if((this->enabled[Mean] || this->enabled[StdDev]) && index < numValues) + { + PiPoValue norm = 1.0 / this->num; + PiPoValue mean = this->sum * norm; + + values[index++] = mean; + + if(this->enabled[StdDev] && index < numValues) + { + PiPoValue mean = this->sum * norm; + PiPoValue meanOfSquare = this->sumOfSquare * norm; + PiPoValue squareOfmean = mean * mean; + PiPoValue stddev; + + if(meanOfSquare > squareOfmean) + stddev = sqrt(meanOfSquare - squareOfmean); + else + stddev = 0.0; + + values[index++] = stddev; + } + } + + if(reset) + this->reset(); + + return index; + } + + return 0; + } + + unsigned int getLabels(const char *name, char **labels, unsigned int strLen, unsigned int numLabels) + { + unsigned int index = 0; + + if(name == NULL) + name = ""; + + if(this->enabled[Min] && index < numLabels) + snprintf(labels[index++], strLen, "%sMin", name); + + if(this->enabled[Max] && index < numLabels) + snprintf(labels[index++], strLen, "%sMax", name); + + if(this->enabled[Mean] && index < numLabels) + snprintf(labels[index++], strLen, "%sMean", name); + + if(this->enabled[StdDev] && index < numLabels) + snprintf(labels[index++], strLen, "%sStdDev", name); + + return index; + } +}; + +class TempModArray +{ +public: + std::vector<TempMod> array; + + TempModArray(unsigned int size = 0) : array(size) + { + } + + ~TempModArray(void) + { + } + + void resize(unsigned int size) + { + this->array.resize(size); + } + + void enable(enum TempMod::ValueId valId, bool enable = true) + { + for(std::vector<TempMod>::iterator iter = this->array.begin(); iter != this->array.end(); iter++) + iter->enable(valId, enable); + } + + void enable(bool minEn, bool maxEn = false, bool meanEn = false, bool stddevEn = false) + { + for(std::vector<TempMod>::iterator iter = this->array.begin(); iter != this->array.end(); iter++) + iter->enable(minEn, maxEn, meanEn, stddevEn); + } + + void select(enum TempMod::ValueId valId) + { + for(std::vector<TempMod>::iterator iter = this->array.begin(); iter != this->array.end(); iter++) + iter->select(valId); + } + + unsigned int getNumValues(void) + { + int numValues = 0; + + for(std::vector<TempMod>::iterator iter = this->array.begin(); iter != this->array.end(); iter++) + numValues += iter->getNumValues(); + + return numValues; + } + + void reset(void) + { + for(std::vector<TempMod>::iterator iter = this->array.begin(); iter != this->array.end(); iter++) + iter->reset(); + }; + + void input(PiPoValue *values, unsigned int numValues) + { + std::vector<TempMod>::iterator iter; + unsigned int i; + + for(iter = this->array.begin(), i = 0; iter != this->array.end() && i < numValues; iter++, i++) + iter->input(values[i]); + }; + + unsigned int getValues(PiPoValue *values, unsigned int numValues, bool reset = false) + { + int totalValues = 0; + std::vector<TempMod>::iterator iter; + + for(iter = this->array.begin(); iter != this->array.end() && numValues > 0; iter++) + { + unsigned int num = iter->getValues(values, numValues, reset); + + totalValues += num; + values += num; + numValues -= num; + } + + return totalValues; + } + + unsigned int getLabels(const char **valueNames, unsigned int numValues, char **labels, unsigned int strLen, unsigned int numLabels) + { + unsigned int totalLabels = 0; + std::vector<TempMod>::iterator iter; + unsigned int i; + + for(iter = this->array.begin(), i = 0; iter != this->array.end() && i < numValues; iter++, i++) + { + unsigned int num; + + if(valueNames != NULL) + num = iter->getLabels(valueNames[i], labels, strLen, numLabels); + else + num = iter->getLabels(NULL, labels, strLen, numLabels); + + totalLabels += num; + labels += num; + numLabels -= num; + } + + return totalLabels; + } +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/mimo/mimo_stats.h b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/mimo/mimo_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..756ea0b133fd711abebe816badce3adb1e34d822 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/pipo/src/modules/mimo/mimo_stats.h @@ -0,0 +1,306 @@ + +#include <string> +#include <sstream> +#include <iostream> +#include <cfloat> +#include <vector> +#include <memory> + +#include "mimo.h" +//#include <picojson.h> + +/* + template <typename Iterable> + Json::Value tojson(Iterable const& cont) { + Json::Value v; + for (auto&& element: cont) { + v.append(element); + } + return v; + } +*/ + +class stats_model_data : public mimo_model_data +{ +public: + std::vector<unsigned long> num; // number of elements present + std::vector<double> mean, std, min, max; + + // helper function for json formatting + template<typename T> + std::string vector2json (std::vector<T> v) + { + std::stringstream ss; + + ss << "["; + for (size_t i = 0; i < v.size(); ++i) + { + if (i != 0) + ss << ","; + ss << v[i]; + } + ss << "]"; + + return ss.str(); + } + + char *to_json (char *out, int n) throw() override + { + std::stringstream ss; + + ss << "{ \"num\": " << vector2json<unsigned long>(num) << "," << std::endl + << " \"min\": " << vector2json<double>(min) << "," << std::endl + << " \"max\": " << vector2json<double>(max) << "," << std::endl + << " \"mean\": " << vector2json<double>(mean) << "," << std::endl + << " \"std\": " << vector2json<double>(std) << "," << std::endl + << "}"; + + std::string ret = ss.str(); + if (ret.size() > n) + throw std::runtime_error("json string too long"); + else + strcpy(out, ret.c_str()); + + return out; + } + + int from_json (const char *json) override + { + // later + return 0; + } +}; + + + +/***************************************************************************** + * + * example mimo module: calculate basic descriptive statistics + * + */ + +class mimo_stats : public Mimo +{ +public: + // constructor + mimo_stats (PiPo::Parent *parent, Mimo *receiver = NULL) + : Mimo(parent, receiver), + distance_(0.0), + alpha(this, "alpha", "Normalization step factor for training iteration", false, 0.1) + { }; + + /** prepare for training, allocate training output data + + @param streamattr attributes of input data + @return 0 for ok or a negative error code (to be specified), -1 for an unspecified error + */ + int setup (int numbuffers, int numtracks, int tracksize[], const PiPoStreamAttributes *streamattr[]) override + { + char astr[1000]; + printf("%s b %d t %d attr:\n%s\n", __PRETTY_FUNCTION__, numbuffers, numtracks, streamattr[0]->to_string(astr, 1000)); + + if (numtracks != 1) + return -1; + + // save for later + numbuffers_ = numbuffers; + stream_ = *streamattr[0]; + bufsize_.assign(tracksize, tracksize + numbuffers); // copy array via pointer iterator + + // set size and fill with 0 + size_ = stream_.dims[0] * stream_.dims[1]; + sum_.assign(size_, 0); + sum2_.assign(size_, 0); + stats_.num.assign(size_, 0); + stats_.mean.resize(size_); + stats_.std.resize(size_); + stats_.min.assign(size_, FLT_MAX); + stats_.max.assign(size_, -FLT_MAX); + + // for the sake of the example: reserve space for training output data when iterating + traindata_.resize(numbuffers_); + for (int i = 0; i < numbuffers_; i++) + traindata_[i].resize(tracksize[i]); + + return propagateSetup(numbuffers, numtracks, tracksize, streamattr); + } + + /** the train method receives the training data set and performs one iteration of training + Each iteration can output transformed input data by calling propagateTrain(). + */ + int train (int itercount, int bufferindex, int trackindex, int numframes, const PiPoValue *indata, const double *timetags, const int *varsize) override + { + const PiPoValue *data = indata; + PiPoValue *outdata; + + printf("%s %d %d %d num %d %p %p %p\n", __PRETTY_FUNCTION__, itercount, bufferindex, trackindex, numframes, data, timetags, varsize); + + if (itercount == 0) + { // for the sake of the example: this mimo module can iterate, but stats are calculated only at first iteration + for (int i = 0; i < numframes; i++) + { + int mtxsize = stream_.hasVarSize ? varsize[i] : size_; + + for (int j = 0; j < mtxsize; j++) + { + PiPoValue val = data[j]; + + stats_.num[j]++; + sum_[j] += val; + sum2_[j] += val * val; + if (val < stats_.min[j]) stats_.min[j] = val; + if (val > stats_.max[j]) stats_.max[j] = val; + } + + data += size_; + } + + // last buffer: finish statistics + if (bufferindex == numbuffers_ - 1) + for (int j = 0; j < size_; j++) + { + stats_.mean[j] = sum_[j] / stats_.num[j]; + stats_.std[j] = sqrt(sum2_[j] / stats_.num[j] - stats_.mean[j] * stats_.mean[j]); + } + } + + // for the sake of the example: when iterating, exponentially approach normalised data: + // multiply by factor attribute alpha, output avg. distance to full normalisation + if (itercount > 0) + { + // check if input track size has changed since setup + if (numframes != bufsize_[bufferindex]) + { + traindata_[bufferindex].resize(numframes); + bufsize_[bufferindex] = numframes; + } + + float factor = alpha.get() * itercount; + data = indata; // indata is always original data, we want to iterate on previous output + outdata = &traindata_[bufferindex][0]; + + for (int i = 0; i < numframes; i++) + { + int mtxsize = stream_.hasVarSize ? varsize[i] : size_; + int j; + double norm; + + for (j = 0; j < mtxsize; j++) + { + if (stats_.std[j] != 0) + norm = (data[j] - stats_.mean[j]) / stats_.std[j]; + else + norm = (data[j] - stats_.mean[j]); + + // banal interpolation + outdata[j] = (1 - factor) * data[j] + factor * norm; + } + + if (i == 0 && mtxsize > 0) printf("normalise %f .. %f -> %f\n", data[j - 1], norm, outdata[j - 1]); + + for (; j < size_; j++) + outdata[j] = 0; + + data += size_; + outdata += size_; + } + + distance_ = 1.0 - factor; + outdata = &traindata_[bufferindex][0]; + } + else // after first iteration, output input data + outdata = (PiPoValue *) indata; + + return propagateTrain(itercount, bufferindex, trackindex, numframes, outdata, timetags, varsize); + } + + /** return trained model parameters */ + stats_model_data *getmodel () override { return &stats_; } + + double getmetric () override { return distance_; } + + int maxiter () override { return 10; } + + + /**************************************************************************** + * decoding: standardise incoming data + */ + + int streamAttributes (bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int height, + const char **labels, bool hasVarSize, + double domain, unsigned int maxFrames) override + { + // check with training attrs + if (width != stream_.dims[0] || height != stream_.dims[1]) + return -1; + + // make labels + const char **newlabels = NULL; + if (labels) + { + const std::string suffix("Norm"); + newlabels = (const char **) alloca(width * sizeof(char *)); + labelstore_.resize(width); + + for (unsigned int i = 0; i < width; i++) + { + labelstore_[i] = std::string(labels[i]) + suffix; + newlabels[i] = labelstore_[i].c_str(); + } + } + + return propagateStreamAttributes(hasTimeTags, rate, offset, width, height, + newlabels, hasVarSize, domain, maxFrames); + } + + + int frames (double time, double weight, PiPoValue *values, unsigned int size, unsigned int num) override + { + bool ok = 1; + + for (unsigned int i = 0; i < num; i++) + { + PiPoValue norm[size]; + + // normalise + for (unsigned int j = 0; j < size; j++) + if (stats_.std[j] != 0) + norm[j] = (values[j] - stats_.mean[j]) / stats_.std[j]; + else + norm[j] = (values[j] - stats_.mean[j]); + + ok &= propagateFrames(time, weight, norm, size, 1) == 0; + + values += size; + } + + return ok ? 0 : -1; + } + + +private: + // training + PiPoStreamAttributes stream_; + int numbuffers_; + int size_; // matrix size + std::vector<int> bufsize_; // num frames for each buffer + std::vector<double> sum_, sum2_; // sum and sum of squares accumulators + stats_model_data stats_; + std::vector<std::string> labelstore_; + std::vector<std::vector<PiPoValue>> traindata_; + double distance_; + + // decoding +public: + PiPoScalarAttr<float> alpha; + //todo: mode attribute: normalise mean/std or min/max +}; + + +/** EMACS ** + * Local variables: + * mode: c + * c-basic-offset:2 + * End: + */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/catch/LICENSE_1_0.txt b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/catch/LICENSE_1_0.txt new file mode 100644 index 0000000000000000000000000000000000000000..127a5bc39ba030c7cb99cc0aedc4f280ffe27310 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/catch/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/catch/catch.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/catch/catch.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2a09fd193a08ce31f5196a62aca40d954356949d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/catch/catch.hpp @@ -0,0 +1,11069 @@ +/* + * Catch v1.7.2 + * Generated: 2017-02-13 15:57:33.350226 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) +// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? +// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_<feature name> form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#ifdef __cplusplus + +# if __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +# endif + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE +#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +// Use __COUNTER__ if the compiler supports it +#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ + ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \ + ( defined __clang__ && __clang_major__ >= 3 ) + +#define CATCH_INTERNAL_CONFIG_COUNTER + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) +# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) +# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif +// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for +// analytics) because, at time of writing, __COUNTER__ is not properly handled by it. +// This does not affect compilation +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_SHUFFLE +#endif +# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TYPE_TRAITS +# endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr<T> +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr<T> +#endif + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include <sstream> +#include <algorithm> + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template<typename ContainerT> + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template<typename AssociativeContainerT> + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo(SourceLineInfo const& other) = default; + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template<typename T> + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include <string> + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template<typename T> + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template<typename T = IShared> + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr<IConfig const> getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr<IConfig const> const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include <vector> + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector<TestCase> const& getAllTests() const = 0; + virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template<typename C> +class MethodTestCase : public SharedImpl<ITestCase> { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template<typename C> + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase<C>( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ + static void TestName(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ + namespace{ \ + struct TestName : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void TestName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ + static void TestName(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ + namespace{ \ + struct TestCaseName : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void TestCaseName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include <string> + +namespace Catch { + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct DecomposedExpression + { + virtual ~DecomposedExpression() {} + virtual bool isBinaryExpression() const { + return false; + } + virtual void reconstructExpression( std::string& dest ) const = 0; + + // Only simple binary comparisons can be decomposed. + // If more complex check is required then wrap sub-expressions in parentheses. + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); + template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); + }; + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : decomposedExpression( CATCH_NULL ) + , resultType( ResultWas::Unknown ) + , negated( false ) + , parenthesized( false ) {} + + void negate( bool parenthesize ) { + negated = !negated; + parenthesized = parenthesize; + if( resultType == ResultWas::Ok ) + resultType = ResultWas::ExpressionFailed; + else if( resultType == ResultWas::ExpressionFailed ) + resultType = ResultWas::Ok; + } + + std::string const& reconstructExpression() const { + if( decomposedExpression != CATCH_NULL ) { + decomposedExpression->reconstructExpression( reconstructedExpression ); + if( parenthesized ) { + reconstructedExpression.insert( 0, 1, '(' ); + reconstructedExpression.append( 1, ')' ); + } + if( negated ) { + reconstructedExpression.insert( 0, 1, '!' ); + } + decomposedExpression = CATCH_NULL; + } + return reconstructedExpression; + } + + mutable DecomposedExpression const* decomposedExpression; + mutable std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + bool negated; + bool parenthesized; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + void discardDecomposedExpression() const; + void expandDecomposedExpression() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template<typename ExpressionT> class AllOf; + template<typename ExpressionT> class AnyOf; + template<typename ExpressionT> class Not; + } + + template<typename ExpressionT> + struct Matcher : SharedImpl<IShared> + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr<Matcher> clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const; + Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const; + Generic::Not<ExpressionT> operator ! () const; + }; + + template<typename DerivedT, typename ExpressionT> + struct MatcherImpl : Matcher<ExpressionT> { + + virtual Ptr<Matcher<ExpressionT> > clone() const { + return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) ); + } + }; + + namespace Generic { + template<typename ExpressionT> + class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> { + public: + explicit Not( Matcher<ExpressionT> const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher<ExpressionT> > m_matcher; + }; + + template<typename ExpressionT> + class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher<ExpressionT> const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher<ExpressionT> const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + }; + + template<typename ExpressionT> + class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher<ExpressionT> const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher<ExpressionT> const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + }; + + } // namespace Generic + + template<typename ExpressionT> + Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const { + Generic::AllOf<ExpressionT> allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template<typename ExpressionT> + Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const { + Generic::AnyOf<ExpressionT> anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template<typename ExpressionT> + Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const { + return Generic::Not<ExpressionT>( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : std::string(); + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl<Equals, std::string> { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + '"' + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl<Contains, std::string> { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + '"' + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl<StartsWith, std::string> { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + '"' + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl<EndsWith, std::string> { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + '"' + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template<typename ExpressionT> + inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) { + return Impl::Generic::Not<ExpressionT>( m ); + } + + template<typename ExpressionT> + inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2 ) { + return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ); + } + template<typename ExpressionT> + inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2, + Impl::Matcher<ExpressionT> const& m3 ) { + return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); + } + template<typename ExpressionT> + inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2 ) { + return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ); + } + template<typename ExpressionT> + inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2, + Impl::Matcher<ExpressionT> const& m3 ) { + return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template<typename T> class ExpressionLhs; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(std::string()); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder : public DecomposedExpression { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template<typename T> + ExpressionLhs<T const&> operator <= ( T const& operand ); + ExpressionLhs<bool> operator <= ( bool value ); + + template<typename T> + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + + void endExpression( DecomposedExpression const& expr ); + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; + + AssertionResult build() const; + AssertionResult build( DecomposedExpression const& expr ) const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + template<typename ArgT, typename MatcherT> + void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include <cstddef> + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } }; + + template<typename T> + inline T& opCast(T const& t) { return const_cast<T&>(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template<typename T1, typename T2, Operator Op> + class Evaluator{}; + + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsNotEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsLessThan> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsGreaterThan> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsLessThanOrEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template<Operator Op, typename T1, typename T2> + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template<Operator Op, typename T1, typename T2> + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); + } + + // unsigned X to int + template<Operator Op> bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + template<Operator Op> bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + template<Operator Op> bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + + // unsigned X to long + template<Operator Op> bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + template<Operator Op> bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + template<Operator Op> bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + + // int to unsigned X + template<Operator Op> bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + template<Operator Op> bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + template<Operator Op> bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + + // long to unsigned X + template<Operator Op> bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template<Operator Op, typename T> bool compare( long lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, long rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template<Operator Op, typename T> bool compare( int lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, int rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template<Operator Op> bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + + // unsigned long long to X + template<Operator Op> bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); + } + template<Operator Op> bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); + } + template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); + } + template<Operator Op> bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include <sstream> +#include <iomanip> +#include <limits> +#include <vector> +#include <cstddef> + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import <Foundation/Foundation.h> + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include <tuple> +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include <type_traits> +#endif + +namespace Catch { + +// Why we're here. +template<typename T> +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template<typename T> BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template<typename T> + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template<typename T, + bool IsEnum = std::is_enum<T>::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template<typename T> + struct EnumStringMaker<T,true> + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast<typename std::underlying_type<T>::type>(v) + ); + } + }; +#endif + template<bool C> + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template<typename T> + static std::string convert( T const& v ) + { + return EnumStringMaker<T>::convert( v ); + } +#else + template<typename T> + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase<true> { + template<typename T> + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template<typename T> + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template<typename T> +struct StringMaker : + Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; + +template<typename T> +struct StringMaker<T*> { + template<typename U> + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template<typename R, typename C> +struct StringMaker<R C::*> { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template<typename InputIterator> + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template<typename T, typename Allocator> +//struct StringMaker<std::vector<T, Allocator> > { +// static std::string convert( std::vector<T,Allocator> const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template<typename T, typename Allocator> +std::string toString( std::vector<T,Allocator> const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size<Tuple>::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get<N>(tuple)); + ElementPrinter<Tuple,N+1>::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter<Tuple,N,false> { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template<typename ...Types> +struct StringMaker<std::tuple<Types...>> { + + static std::string convert( const std::tuple<Types...>& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template<typename T> + std::string makeString( T const& value ) { + return StringMaker<T>::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template<typename T> +std::string toString( T const& value ) { + return StringMaker<T>::convert( value ); +} + + namespace Detail { + template<typename InputIterator> + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +template<typename LhsT, Internal::Operator Op, typename RhsT> +class BinaryExpression; + +template<typename ArgT, typename MatcherT> +class MatchExpression; + +// Wraps the LHS of an expression and overloads comparison operators +// for also capturing those and RHS (if any) +template<typename T> +class ExpressionLhs : public DecomposedExpression { +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} + + template<typename RhsT> + BinaryExpression<T, Internal::IsEqualTo, RhsT const&> + operator == ( RhsT const& rhs ) { + return captureExpression<Internal::IsEqualTo>( rhs ); + } + + template<typename RhsT> + BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&> + operator != ( RhsT const& rhs ) { + return captureExpression<Internal::IsNotEqualTo>( rhs ); + } + + template<typename RhsT> + BinaryExpression<T, Internal::IsLessThan, RhsT const&> + operator < ( RhsT const& rhs ) { + return captureExpression<Internal::IsLessThan>( rhs ); + } + + template<typename RhsT> + BinaryExpression<T, Internal::IsGreaterThan, RhsT const&> + operator > ( RhsT const& rhs ) { + return captureExpression<Internal::IsGreaterThan>( rhs ); + } + + template<typename RhsT> + BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&> + operator <= ( RhsT const& rhs ) { + return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); + } + + template<typename RhsT> + BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&> + operator >= ( RhsT const& rhs ) { + return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); + } + + BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) { + return captureExpression<Internal::IsEqualTo>( rhs ); + } + + BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) { + return captureExpression<Internal::IsNotEqualTo>( rhs ); + } + + void endExpression() { + m_truthy = m_lhs ? true : false; + m_rb + .setResultType( m_truthy ) + .endExpression( *this ); + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + dest = Catch::toString( m_truthy ); + } + +private: + template<Internal::Operator Op, typename RhsT> + BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const { + return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs ); + } + + template<Internal::Operator Op> + BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const { + return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; + bool m_truthy; +}; + +template<typename LhsT, Internal::Operator Op, typename RhsT> +class BinaryExpression : public DecomposedExpression { +public: + BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) + : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} + + void endExpression() const { + m_rb + .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) ) + .endExpression( *this ); + } + + virtual bool isBinaryExpression() const CATCH_OVERRIDE { + return true; + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + std::string lhs = Catch::toString( m_lhs ); + std::string rhs = Catch::toString( m_rhs ); + char delim = lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ? ' ' : '\n'; + dest.reserve( 7 + lhs.size() + rhs.size() ); + // 2 for spaces around operator + // 2 for operator + // 2 for parentheses (conditionally added later) + // 1 for negation (conditionally added later) + dest = lhs; + dest += delim; + dest += Internal::OperatorTraits<Op>::getName(); + dest += delim; + dest += rhs; + } + +private: + ResultBuilder& m_rb; + LhsT m_lhs; + RhsT m_rhs; +}; + +template<typename ArgT, typename MatcherT> +class MatchExpression : public DecomposedExpression { +public: + MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) + : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} + + virtual bool isBinaryExpression() const CATCH_OVERRIDE { + return true; + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + std::string matcherAsString = m_matcher.toString(); + dest = Catch::toString( m_arg ); + dest += ' '; + if( matcherAsString == Detail::unprintableString ) + dest += m_matcherString; + else + dest += matcherAsString; + } + +private: + ArgT m_arg; + MatcherT m_matcher; + char const* m_matcherString; +}; + +} // end namespace Catch + + +namespace Catch { + + template<typename T> + inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs<T const&>( *this, operand ); + } + + inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs<bool>( *this, value ); + } + + template<typename ArgT, typename MatcherT> + inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, + char const* matcherString ) { + MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString ); + setResultType( matcher.match( arg ) ); + endExpression( expr ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include <string> + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template<typename T> + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include <string> + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# define CATCH_PLATFORM_IPHONE +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +# define CATCH_PLATFORM_WINDOWS +# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINES_NOMINMAX +# endif +# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# endif +#endif + +#include <string> + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_TRAP() \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ) + #else + #define CATCH_TRAP() __asm__("int $3\n" : : ) + #endif + +#elif defined(CATCH_PLATFORM_LINUX) + // If we can use inline assembler, do it because this allows us to break + // directly at the location of the failing check instead of breaking inside + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") + #else // Fall back to the generic way. + #include <signal.h> + + #define CATCH_TRAP() raise(SIGTRAP) + #endif +#elif defined(_MSC_VER) + #define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_TRAP() DebugBreak() +#endif + +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +// #included from: catch_type_traits.hpp +#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED + +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) +#include <type_traits> +#endif + +namespace Catch { + +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) + + template <typename T> + using add_lvalue_reference = std::add_lvalue_reference<T>; + + template <typename T> + using add_const = std::add_const<T>; + +#else + + template <typename T> + struct add_const { + typedef const T type; + }; + + template <typename T> + struct add_lvalue_reference { + typedef T& type; + }; + template <typename T> + struct add_lvalue_reference<T&> { + typedef T& type; + }; + // No && overload, because that is C++11, in which case we have + // proper type_traits implementation from the standard library + +#endif + +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + static_cast<void>(expr); \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + static_cast<void>(expr); \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + static_cast<void>(expr); \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( Catch::add_const<Catch::add_lvalue_reference<exceptionType>::type>::type ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + __catchResult.captureMatch( arg, matcher, #matcher ); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include <cstddef> + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +#include <string> + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include <stdint.h> +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include <string> + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include <iterator> +#include <vector> +#include <string> +#include <stdlib.h> + +namespace Catch { + +template<typename T> +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template<typename T> +class BetweenGenerator : public IGenerator<T> { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast<int>( index ); + } + + virtual std::size_t size() const { + return static_cast<std::size_t>( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template<typename T> +class ValuesGenerator : public IGenerator<T> { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector<T> m_values; +}; + +template<typename T> +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); + typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator<T>* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator<T>* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector<const IGenerator<T>*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template<typename T> + CompositeGenerator<T> between( T from, T to ) { + CompositeGenerator<T> generators; + generators.add( new BetweenGenerator<T>( from, to ) ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2 ) { + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2, T val3 ){ + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include <string> +#include <vector> + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include <string> + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0; + virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector<const IExceptionTranslator*> ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template<typename T> + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template<typename T> + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator<T>( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ + static std::string translatorName( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ + static std::string translatorName( signature ) + +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include <cmath> +#include <limits> + +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) +#include <type_traits> +#endif + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator == ( const T& lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + auto lhs_v = double(lhs); + return std::fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs_v), std::fabs(rhs.m_value) ) ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator == ( Approx const& lhs, const T& rhs ) { + return operator==( rhs, lhs ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator != ( T lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator != ( Approx const& lhs, T rhs ) { + return !operator==( rhs, lhs ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator <= ( T lhs, Approx const& rhs ) + { + return double(lhs) < rhs.m_value || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator <= ( Approx const& lhs, T rhs ) + { + return lhs.m_value < double(rhs) || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator >= ( T lhs, Approx const& rhs ) + { + return double(lhs) > rhs.m_value || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator >= ( Approx const& lhs, T rhs ) + { + return lhs.m_value > double(rhs) || lhs == rhs; + } +#else + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + friend bool operator <= ( double lhs, Approx const& rhs ) + { + return lhs < rhs.m_value || lhs == rhs; + } + + friend bool operator <= ( Approx const& lhs, double rhs ) + { + return lhs.m_value < rhs || lhs == rhs; + } + + friend bool operator >= ( double lhs, Approx const& rhs ) + { + return lhs > rhs.m_value || lhs == rhs; + } + + friend bool operator >= ( Approx const& lhs, double rhs ) + { + return lhs.m_value > rhs || lhs == rhs; + } +#endif + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString<Detail::Approx>( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include <string> + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template<typename T> + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option<TagAlias> find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include <string> +#include <set> + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4, + NonPortable = 1 << 5 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set<std::string> const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set<std::string> tags; + std::set<std::string> lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr<ITestCase> test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import <objc/runtime.h> + +#include <string> + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl<ITestCase> { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template<typename MatcherT> + struct StringHolder : MatcherImpl<MatcherT, NSString*>{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder<Equals> { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder<Contains> { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder<StartsWith> { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder<EndsWith> { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +#include <stdexcept> + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include <string> +#include <vector> + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr<Pattern> m_underlyingPattern; + }; + + struct Filter { + std::vector<Ptr<Pattern> > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { + if( !(*it)->matches( testCase ) ) + return false; + } + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector<Filter> m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag, EscapedName }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + std::vector<std::size_t> m_escapeChars; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern<TestSpec::NamePattern>(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern<TestSpec::NamePattern>(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern<TestSpec::NamePattern>(); + startNewMode( Tag, ++m_pos ); + } + else if( c == '\\' ) + escape(); + } + else if( m_mode == EscapedName ) + m_mode = Name; + else if( m_mode == QuotedName && c == '"' ) + addPattern<TestSpec::NamePattern>(); + else if( m_mode == Tag && c == ']' ) + addPattern<TestSpec::TagPattern>(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + void escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template<typename T> + void addPattern() { + std::string token = subString(); + for( size_t i = 0; i < m_escapeChars.size(); ++i ) + token = token.substr( 0, m_escapeChars[i]-i ) + token.substr( m_escapeChars[i]+1-i ); + m_escapeChars.clear(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr<TestSpec::Pattern> pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include <iosfwd> +#include <string> +#include <vector> + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector<std::string> const& getSectionsToRun() const = 0; + + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include <streambuf> + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include <streambuf> +#include <ostream> +#include <fstream> +#include <memory> + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include <memory> +#include <vector> +#include <string> +#include <stdexcept> + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector<std::string> reporterNames; + std::vector<std::string> testsOrTags; + std::vector<std::string> sectionsToRun; + }; + + class Config : public SharedImpl<IConfig> { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() {} + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; } + std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } + + virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + + // IConfig interface + virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } + virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } + virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } + virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } + virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } + virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } + virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + CATCH_AUTO_PTR( IStream const ) m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.2.4 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include <string> +#include <vector> +#include <sstream> +#include <algorithm> + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector<std::string>::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector<std::string> lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_<feature name> form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr<T> +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr<T> +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include <map> +#include <stdexcept> +#include <memory> + +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CLARA_PLATFORM_WINDOWS +#endif + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template<typename T> struct RemoveConstRef{ typedef T type; }; + template<typename T> struct RemoveConstRef<T&>{ typedef T type; }; + template<typename T> struct RemoveConstRef<T const&>{ typedef T type; }; + template<typename T> struct RemoveConstRef<T const>{ typedef T type; }; + + template<typename T> struct IsBool { static const bool value = false; }; + template<> struct IsBool<bool> { static const bool value = true; }; + + template<typename T> + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + char toLowerCh(char c) { + return static_cast<char>( ::tolower( c ) ); + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + + template<typename ConfigT> + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template<typename ConfigT> + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction<ConfigT>* functionObj; + }; + + template<typename C> + struct NullBinder : IArgFunction<C>{ + virtual void set( C&, std::string const& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } + }; + + template<typename C, typename M> + struct BoundDataMember : IArgFunction<C>{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual bool takesArg() const { return !IsBool<M>::value; } + virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template<typename C, typename M> + struct BoundUnaryMethod : IArgFunction<C>{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef<M>::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool<M>::value; } + virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template<typename C> + struct BoundNullaryMethod : IArgFunction<C>{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template<typename C> + struct BoundUnaryFunction : IArgFunction<C>{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template<typename C, typename T> + struct BoundBinaryFunction : IArgFunction<C>{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef<T>::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool<T>::value; } + virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) { + std::vector<std::string> args( static_cast<std::size_t>( argc ) ); + for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i ) + args[i] = argv[i]; + + return args; + } + + class Parser { + enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; + Mode mode; + std::size_t from; + bool inQuotes; + public: + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + Parser() : mode( None ), from( 0 ), inQuotes( false ){} + + void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) { + const std::string doubleDash = "--"; + for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) + parseIntoTokens( args[i], tokens); + } + + void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) { + for( std::size_t i = 0; i <= arg.size(); ++i ) { + char c = arg[i]; + if( c == '"' ) + inQuotes = !inQuotes; + mode = handleMode( i, c, arg, tokens ); + } + } + Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { + switch( mode ) { + case None: return handleNone( i, c ); + case MaybeShortOpt: return handleMaybeShortOpt( i, c ); + case ShortOpt: + case LongOpt: + case SlashOpt: return handleOpt( i, c, arg, tokens ); + case Positional: return handlePositional( i, c, arg, tokens ); + default: throw std::logic_error( "Unknown mode" ); + } + } + + Mode handleNone( std::size_t i, char c ) { + if( inQuotes ) { + from = i; + return Positional; + } + switch( c ) { + case '-': return MaybeShortOpt; +#ifdef CLARA_PLATFORM_WINDOWS + case '/': from = i+1; return SlashOpt; +#endif + default: from = i; return Positional; + } + } + Mode handleMaybeShortOpt( std::size_t i, char c ) { + switch( c ) { + case '-': from = i+1; return LongOpt; + default: from = i; return ShortOpt; + } + } + Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { + if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) + return mode; + + std::string optName = arg.substr( from, i-from ); + if( mode == ShortOpt ) + for( std::size_t j = 0; j < optName.size(); ++j ) + tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); + else if( mode == SlashOpt && optName.size() == 1 ) + tokens.push_back( Token( Token::ShortOpt, optName ) ); + else + tokens.push_back( Token( Token::LongOpt, optName ) ); + return None; + } + Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { + if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) + return mode; + + std::string data = arg.substr( from, i-from ); + tokens.push_back( Token( Token::Positional, data ) ); + return None; + } + }; + + template<typename ConfigT> + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction<ConfigT> boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector<std::string> shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template<typename ConfigT> + class CommandLine { + + struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {} + + using CommonArgProperties<ConfigT>::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template<typename C, typename M> + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember<C,M>( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template<typename C> + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember<C,bool>( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template<typename C, typename M> + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template<typename C> + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template<typename C> + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template<typename C> + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template<typename C, typename T> + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder<ConfigT>() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template<typename C, typename M> + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember<C,M>( field ); + } + template<typename C, typename M> + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( std::vector<std::string> const& args ) const { + ConfigT config; + parseInto( args, config ); + return config; + } + + std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const { + std::string processName = args[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector<Parser::Token> tokens; + Parser parser; + parser.parseIntoTokens( args, tokens ); + return populate( tokens, config ); + } + + std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + validate(); + std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + std::vector<Parser::Token> unusedTokens; + std::vector<std::string> errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.set( config, "true" ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + std::vector<Parser::Token> unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector<Parser::Token> unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector<Arg>::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction<ConfigT> m_boundProcessName; + std::vector<Arg> m_options; + std::map<int, Arg> m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include <fstream> +#include <ctime> + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast<unsigned int>( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast<Verbosity::Level>( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + addTestOrTags( config, line + ',' ); + } + } + } + + inline Clara::CommandLine<ConfigData> makeCommandLineParser() { + + using namespace Clara; + CommandLine<ConfigData> cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + cli["-c"]["--section"] + .describe( "specify section to run" ) + .bind( &addSectionToRun, "section name" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include <string> +#include <vector> +#include <sstream> + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + const std::string wrappableBeforeChars = "[({<\t"; + const std::string wrappableAfterChars = "])}>-,./|\\"; + const std::string wrappableInsteadOfChars = " \n\r"; + std::string indent = _attr.initialIndent != std::string::npos + ? std::string( _attr.initialIndent, ' ' ) + : std::string( _attr.indent, ' ' ); + + typedef std::string::const_iterator iterator; + iterator it = _str.begin(); + const iterator strEnd = _str.end(); + + while( it != strEnd ) { + + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + + std::string suffix; + std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) ); + iterator itEnd = it+width; + iterator itNext = _str.end(); + + iterator itNewLine = std::find( it, itEnd, '\n' ); + if( itNewLine != itEnd ) + itEnd = itNewLine; + + if( itEnd != strEnd ) { + bool foundWrapPoint = false; + iterator findIt = itEnd; + do { + if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { + itEnd = findIt+1; + itNext = findIt+1; + foundWrapPoint = true; + } + else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { + itEnd = findIt; + itNext = findIt; + foundWrapPoint = true; + } + else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { + itNext = findIt+1; + itEnd = findIt; + foundWrapPoint = true; + } + if( findIt == it ) + break; + else + --findIt; + } + while( !foundWrapPoint ); + + if( !foundWrapPoint ) { + // No good wrap char, so we'll break mid word and add a hyphen + --itEnd; + itNext = itEnd; + suffix = "-"; + } + else { + while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) + --itEnd; + } + } + lines.push_back( indent + std::string( it, itEnd ) + suffix ); + + if( indent.size() != _attr.indent ) + indent = std::string( _attr.indent, ' ' ); + it = itNext; + } + } + + typedef std::vector<std::string>::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector<std::string> lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include <string> +#include <ostream> +#include <map> + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr<IConfig const> fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr<IConfig const> m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template<typename T> + struct LazyStat : Option<T> { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option<T>::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option<T>::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector<MessageInfo> const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector<MessageInfo> infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + class MultipleReporters; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap; + typedef std::vector<Ptr<IReporterFactory> > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ); + +} + +#include <limits> +#include <algorithm> + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl; + else + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set<std::string> spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map<std::string, TagInfo> tagCounts; + + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ':' + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << '\n'; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option<std::size_t> list( Config const& config ) { + Option<std::size_t> listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include <map> +#include <string> +#include <assert.h> +#include <vector> +#include <iterator> +#include <stdexcept> + +namespace Catch { +namespace TestCaseTracking { + + struct NameAndLocation { + std::string name; + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} + }; + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual NameAndLocation const& nameAndLocation() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr<ITracker> const& child ) = 0; + virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr<ITracker> m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + NameAndLocation m_nameAndLocation; + public: + TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} + bool operator ()( Ptr<ITracker> const& tracker ) { + return + tracker->nameAndLocation().name == m_nameAndLocation.name && + tracker->nameAndLocation().location == m_nameAndLocation.location; + } + }; + typedef std::vector<Ptr<ITracker> > Children; + NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { + return m_nameAndLocation; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + + virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } + virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } + + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + std::vector<std::string> m_filters; + public: + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); + + SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); + addNextFilters( parentSection.m_filters ); + } + } + virtual ~SectionTracker(); + + virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } + + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = static_cast<SectionTracker*>( childTracker ); + } + else { + section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } + + void addInitialFilters( std::vector<std::string> const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) ); + } + } + void addNextFilters( std::vector<std::string> const& filters ) { + if( filters.size() > 1 ) + std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) ); + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } + + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = static_cast<IndexTracker*>( childTracker ); + } + else { + tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition + inline void reportFatal( std::string const& message ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// +// #included from: catch_windows_h_proxy.h + +#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED + +#ifdef CATCH_DEFINES_NOMINMAX +# define NOMINMAX +#endif +#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include <AfxWin.h> +#else +#include <windows.h> +#endif + +#ifdef CATCH_DEFINES_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + + +# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct FatalConditionHandler { + void reset() {} + }; +} + +# else // CATCH_CONFIG_WINDOWS_SEH is defined + +namespace Catch { + + struct SignalDefs { DWORD id; const char* name; }; + extern SignalDefs signalDefs[]; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reset(); + reportFatal(signalDefs[i].name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = CATCH_NULL; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + static void reset() { + if (isSet) { + // Unregister handler and restore the old guarantee + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = CATCH_NULL; + isSet = false; + } + } + + ~FatalConditionHandler() { + reset(); + } + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; + +} // namespace Catch + +# endif // CATCH_CONFIG_WINDOWS_SEH + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include <signal.h> + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; + static stack_t oldSigStack; + static char altStackMem[SIGSTKSZ]; + + static void handleSignal( int sig ) { + std::string name = "<unknown signal>"; + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + SignalDefs &def = signalDefs[i]; + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); + } + + FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = SIGSTKSZ; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { 0 }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + ~FatalConditionHandler() { + reset(); + } + static void reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); + } + // Return the old stack + sigaltstack(&oldSigStack, CATCH_NULL); + isSet = false; + } + } + }; + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; + +} // namespace Catch + +#endif // not Windows + +#include <set> +#include <string> + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + ITracker& rootTracker = m_trackerContext.startRun(); + assert( rootTracker.isSectionTracker() ); + static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr<IConfig const> config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + std::string(), + std::string(), + false ) ); + m_totals.testCases.failed++; + testGroupEnded( std::string(), m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr<IConfig const> m_config; + Totals m_totals; + Ptr<IStreamingReporter> m_reporter; + std::vector<MessageInfo> m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector<SectionEndInfo> m_unfinishedSections; + std::vector<ITracker*> m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include <fstream> +#include <stdlib.h> +#include <limits> + +namespace Catch { + + Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) { + Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) { + std::vector<std::string> reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr<IStreamingReporter> reporter; + for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr<Config> const& config ) { + + Ptr<IConfig const> iconfig = config.get(); + + Ptr<IStreamingReporter> reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector<TestCase> const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast<TestCase&>( tests[i] ); + std::set<std::string> tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits<int>::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* const* const argv ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option<std::size_t> listed = list( config() ) ) + return static_cast<int>( *listed ); + + return static_cast<int>( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits<int>::max)(); + } + } + + Clara::CommandLine<ConfigData> const& cli() const { + return m_cli; + } + std::vector<Clara::Parser::Token> const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine<ConfigData> m_cli; + std::vector<Clara::Parser::Token> m_unusedTokens; + ConfigData m_configData; + Ptr<Config> m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include <vector> +#include <set> +#include <sstream> +#include <algorithm> + +namespace Catch { + + struct RandomNumberGenerator { + typedef std::ptrdiff_t result_type; + + result_type operator()( result_type n ) const { return std::rand() % n; } + +#ifdef CATCH_CONFIG_CPP11_SHUFFLE + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return 1000000; } + result_type operator()() const { return std::rand() % max(); } +#endif + template<typename V> + static void shuffle( V& vector ) { + RandomNumberGenerator rng; +#ifdef CATCH_CONFIG_CPP11_SHUFFLE + std::shuffle( vector.begin(), vector.end(), rng ); +#else + std::random_shuffle( vector.begin(), vector.end(), rng ); +#endif + } + }; + + inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { + + std::vector<TestCase> sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + RandomNumberGenerator::shuffle( sorted ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { + std::set<TestCase> seenFunctions; + for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ) { + std::ostringstream ss; + + ss << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + + throw std::runtime_error(ss.str()); + } + } + } + + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector<TestCase> filtered; + filtered.reserve( testCases.size() ); + for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector<TestCase> const& getAllTests() const { + return m_functions; + } + virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector<TestCase> m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector<TestCase> m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl<ITestCase> { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include <map> + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr<IReporterFactory> const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector<const IExceptionTranslator*> m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include <sstream> + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include <stdexcept> +#include <cstdio> +#include <iostream> + +namespace Catch { + + template<typename WriterF, size_t bufferSize=256> + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast<char>( c ) ) ); + else + sputc( static_cast<char>( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << '\''; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: + virtual ~Context() { + deleteAllValues( m_generatorsByTestName ); + } + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr<IConfig const> getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr<IConfig const> const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map<std::string, IGeneratorsForTest*>::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr<IConfig const> m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr<IConfig const> config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include <unistd.h> + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0;34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr<IConfig const> config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include <vector> +#include <string> +#include <map> + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin(); + std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map<std::string, IGeneratorInfo*> m_generatorsByName; + std::vector<IGeneratorInfo*> m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return '!' + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructExpression(); + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + + void AssertionResult::discardDecomposedExpression() const { + m_resultData.decomposedExpression = CATCH_NULL; + } + + void AssertionResult::expandDecomposedExpression() const { + m_resultData.reconstructExpression(); + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +#include <cctype> + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set<std::string> tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << '[' << *it << ']'; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set<std::string> const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << '-' << version.branchName + << '.' << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 7, 2, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl<IStreamingReporter> + { + public: + LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr<IReporter> m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#else +#include <sys/time.h> +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) ); + QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast<unsigned int>(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast<unsigned int>(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +#include <cstring> +#include <cctype> + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + char toLowerCh(char c) { + return static_cast<char>( std::tolower( c ) ); + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + + SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + bool SourceLineInfo::empty() const { + return file[0] == '\0'; + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << '\''; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#ifdef CATCH_PLATFORM_MAC + + #include <assert.h> + #include <stdbool.h> + #include <sys/types.h> + #include <unistd.h> + #include <sys/sysctl.h> + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(CATCH_PLATFORM_LINUX) + #include <fstream> + #include <string> + + namespace Catch{ + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive(){ + std::ifstream in("/proc/self/status"); + for( std::string line; std::getline(in, line); ) { + static const int PREFIX_LEN = 11; + if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + + return false; + } + } // namespace Catch +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast<int>( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast<unsigned char const *>(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast<unsigned>(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return '"' + s + '"'; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast<const char*>( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast<const wchar_t*>( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast<unsigned long>( value ) ); +} + +template<typename T> +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + 'f'; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + if ( value == '\r' ) + return "'\\r'"; + if ( value == '\f' ) + return "'\\f'"; + if ( value == '\n' ) + return "'\\n'"; + if ( value == '\t' ) + return "'\\t'"; + if ( '\0' <= value && value < ' ' ) + return toString( static_cast<unsigned int>( value ) ); + char chstr[] = "' '"; + chstr[1] = value; + return chstr; +} + +std::string toString( signed char value ) { + return toString( static_cast<char>( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast<char>( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + + void ResultBuilder::endExpression( DecomposedExpression const& expr ) { + AssertionResult result = build( expr ); + handleResult( result ); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) { + + assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + return build( *this ); + } + + // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, + // a temporary DecomposedExpression, which in turn holds references to + // operands, possibly temporary as well. + // It should immediately be passed to handleResult; if the expression + // needs to be reported, its string expansion must be composed before + // the temporaries are destroyed. + AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const + { + assert( m_data.resultType != ResultWas::Unknown ); + AssertionResultData data = m_data; + + // Flip bool results if FalseTest flag is set + if( isFalseTest( m_assertionInfo.resultDisposition ) ) { + data.negate( expr.isBinaryExpression() ); + } + + data.message = m_stream.oss.str(); + data.decomposedExpression = &expr; // for lazy reconstruction + return AssertionResult( m_assertionInfo, data ); + } + + void ResultBuilder::reconstructExpression( std::string& dest ) const { + dest = m_assertionInfo.capturedExpression; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include <map> + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option<TagAlias> find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map<std::string, TagAlias> m_registry; + }; + +} // end namespace Catch + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const { + std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option<TagAlias>(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << '\n' + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl<IStreamingReporter> { + typedef std::vector<Ptr<IStreamingReporter> > Reporters; + Reporters m_reporters; + +public: + void add( Ptr<IStreamingReporter> const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } + + virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { + return this; + } + +}; + +Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { + Ptr<IStreamingReporter> resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = existingReporter->tryAsMulti(); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr<IStreamingReporter>( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include <cstring> + +namespace Catch { + + struct StreamingReporterBase : SharedImpl<IStreamingReporter> { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr<IConfig const> m_config; + std::ostream& stream; + + LazyStat<TestRunInfo> currentTestRunInfo; + LazyStat<GroupInfo> currentGroupInfo; + LazyStat<TestCaseInfo> currentTestCaseInfo; + + std::vector<SectionInfo> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl<IStreamingReporter> { + template<typename T, typename ChildNodeT> + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector<Ptr<ChildNodeT> > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr<SectionNode> const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector<Ptr<SectionNode> > ChildSections; + typedef std::vector<AssertionStats> Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr<SectionNode> const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node<TestCaseStats, SectionNode> TestCaseNode; + typedef Node<TestGroupStats, TestCaseNode> TestGroupNode; + typedef Node<TestRunStats, TestGroupNode> TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr<SectionNode> node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr<TestRunNode> node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void prepareExpandedExpression( AssertionResult& result ) const { + if( result.isOk() ) + result.discardDecomposedExpression(); + else + result.expandDecomposedExpression(); + } + + Ptr<IConfig const> m_config; + std::ostream& stream; + std::vector<AssertionStats> m_assertions; + std::vector<std::vector<Ptr<SectionNode> > > m_sections; + std::vector<Ptr<TestCaseNode> > m_testCases; + std::vector<Ptr<TestGroupNode> > m_testGroups; + + std::vector<Ptr<TestRunNode> > m_testRuns; + + Ptr<SectionNode> m_rootSection; + Ptr<SectionNode> m_deepestSection; + std::vector<Ptr<SectionNode> > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template<char C> + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template<typename T> + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template<typename T> + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl<IReporterFactory> { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template<typename T> + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl<IReporterFactory> { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return std::string(); + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include <sstream> +#include <string> +#include <vector> +#include <iomanip> + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 + if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast<int>( c ); + } + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template<typename T> + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( Catch::cout() ) + { + writeDeclaration(); + } + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( os ) + { + writeDeclaration(); + } + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << "</" << m_tags.back() << ">"; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + template<typename T> + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + m_os << m_indent << "<!--" << text << "-->"; + m_needsNewline = true; + return *this; + } + + void writeStylesheetRef( std::string const& url ) { + m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n"; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + void writeDeclaration() { + m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector<std::string> m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + virtual std::string getStylesheetRef() const { + return std::string(); + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + m_xml.ensureTagClosed(); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in <Info> tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "FatalErrorCondition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include <assert.h> + +namespace Catch { + + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif + + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + + } + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << '\n'; + for( std::vector<MessageInfo>::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << '\n'; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << 's' << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << 's' << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << '\n'; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << '\n'; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ':' << '\n'; + for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector<MessageInfo> messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector<SectionInfo>::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << '\n'; + } + stream << getLineOfChars<'.'>() << '\n' << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << '\n'; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << '\n'; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = ' ' + *it; + while( it->size() > row.size() ) + row = ' ' + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector<std::string> rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ')' + << '\n'; + } + else { + + std::vector<SummaryColumn> columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) { + for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << ' ' << it->label; + } + } + stream << '\n'; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << '\n'; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << '\n'; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ':'; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } + + void printIssue( std::string issue ) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ';'; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << ' ' << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector<MessageInfo>::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ':'; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << '\''; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector<MessageInfo> messages; + std::vector<MessageInfo>::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? std::string() : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : std::string(); + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << '.'; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + int result = Catch::Session().run( argc, argv ); + return ( result < 0xff ? result : 0xff ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return ( result < 0xff ? result : 0xff ); +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/json/json-forwards.h b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/json/json-forwards.h new file mode 100644 index 0000000000000000000000000000000000000000..65e8dfb295dc0356836484b59c56b9e3c010b741 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/json/json-forwards.h @@ -0,0 +1,324 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// 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_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 +#include <stddef.h> +#include <string> //typedef String +#include <stdint.h> //typedef int64_t, uint64_t + +/// 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 non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// 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 <cpptl/config.h> +#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) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#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) // MSVC +# if _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 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +#elif defined(_MSC_VER) && _MSC_VER > 1600 +# define JSONCPP_OVERRIDE override +#else +# define JSONCPP_OVERRIDE +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +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 int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // 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; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/json/json.h b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/json/json.h new file mode 100644 index 0000000000000000000000000000000000000000..de79502eebdf122bcbecaf0516b4de10409f44f6 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/json/json.h @@ -0,0 +1,2140 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// 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/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "1.7.7" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 7 +# define JSONCPP_VERSION_PATCH 7 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// 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 +#include <stddef.h> +#include <string> //typedef String +#include <stdint.h> //typedef int64_t, uint64_t + +/// 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 non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// 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 <cpptl/config.h> +#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) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#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) // MSVC +# if _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 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +#elif defined(_MSC_VER) && _MSC_VER > 1600 +# define JSONCPP_OVERRIDE override +#else +# define JSONCPP_OVERRIDE +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +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 int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // 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; + +} // 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_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // 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 <string> +#include <vector> +#include <exception> + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include <map> +#else +#include <cpptl/smallmap.h> +#endif +#ifdef JSON_USE_CPPTL +#include <cpptl/forwards.h> +#endif + +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() throw() JSONCPP_OVERRIDE; + char const* what() const throw() JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + +/** \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<const char *> EnumMemberNames; +// typedef CppTL::AnyEnumerator<const Value &> 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) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a <a HREF="http://www.json.org">JSON</a> 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 resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain 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. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector<JSONCPP_STRING> 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; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// 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; + +#if defined(JSON_HAS_INT64) + /// 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; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(CZString other); + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map<CZString, Value> ObjectValues; +#else + typedef CppTL::SmallMap<CZString, Value> ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#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); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \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. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value& operator=(Value other); + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + 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; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + 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 isInt64() const; + bool isUInt() const; + bool isUInt64() 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. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + 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. + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has 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. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \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 + /// \deprecated + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + Value removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) 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 + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + 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_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const JSONCPP_STRING& key); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + JSONCPP_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 JSON_API Path { +public: + Path(const JSONCPP_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<const PathArgument*> InArgs; + typedef std::vector<PathArgument> Args; + + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const JSONCPP_STRING& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + 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 other.computeDistance(*this); + } + + /// 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, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) 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: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +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(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +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(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#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 <deque> +#include <iosfwd> +#include <stack> +#include <string> +#include <istream> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \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 <a HREF="http://www.json.org">JSON</a> + * 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 <a HREF="http://www.json.org">JSON</a> + 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(JSONCPP_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.") + JSONCPP_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. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector<StructuredError> getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() 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_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque<ErrorInfo> Errors; + + 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 decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack<Value*> Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \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 errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, std::string* errs); + +/** \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<<() +*/ +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#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 <vector> +#include <string> +#include <ostream> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr<StreamWriter> const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr<Json::StreamWriter> writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "<anything>" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual JSONCPP_STRING write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> 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 + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API FastWriter : public Writer { + +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's Javascript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatiblityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> 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() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +public: // overridden from Writer + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> 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() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledStreamWriter { +public: + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> 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(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.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_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include <stdlib.h> +#include <sstream> + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/jsoncpp.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/jsoncpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ec7dded8d504e575660c506615efced908efeb4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/jsoncpp.cpp @@ -0,0 +1,5290 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// 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 +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" + +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// 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 + +#ifndef NO_LOCALE_SUPPORT +#include <clocale> +#endif + +/* 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 { +static char getDecimalPoint() { +#ifdef NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast<char>(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast<char>(0x80 | (0x3f & cp)); + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast<char>(0x80 | (0x3f & cp)); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast<char>(0x80 | (0x3f & cp)); + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +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*& current) { + *--current = 0; + do { + *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +static inline void fixNumericLocaleInput(char* begin, char* end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint != '\0' && decimalPoint != '.') { + while (begin < end) { + if (*begin == '.') { + *begin = decimalPoint; + } + ++begin; + } + } +} + +} // 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-2011 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 <json/assertions.h> +#include <json/reader.h> +#include <json/value.h> +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <utility> +#include <cstdio> +#include <cassert> +#include <cstring> +#include <istream> +#include <sstream> +#include <memory> +#include <set> +#include <limits> + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +static int const stackLimit_g = 1000; +static int stackDepth_g = 0; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<CharReader> CharReaderPtr; +#else +typedef std::auto_ptr<CharReader> CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +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() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool +Reader::parse(const std::string& document, Value& root, bool collectComments) { + JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); + std::swap(documentCopy, 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<char> begin(sin); + // std::istream_iterator<char> end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(sin, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), 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); + + stackDepth_g = 0; // Yes, this is bad coding, but options are limited. + 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() { + // This is a non-reentrant way to support a stackLimit. Terrible! + // But this deprecated class has a security problem: Bad input can + // cause a seg-fault. This seems like a fair, binary-compatible way + // to prevent the problem. + if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_g; + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_g; + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +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; +} + +static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast<size_t>(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +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; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); + } else { + break; + } + + 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) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *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) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // 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; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast<Value::UInt>(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast<size_t>(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& current, + 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& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int 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); + } + ret_unicode = static_cast<unsigned int>(unicode); + return true; +} + +bool +Reader::addError(const JSONCPP_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) { + size_t const errorCount = 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 JSONCPP_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; +} + +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +JSONCPP_STRING Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_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::vector<Reader::StructuredError> Reader::getStructuredErrors() const { + std::vector<Reader::StructuredError> allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { + return !errors_.size(); +} + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector<StructuredError> getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque<ErrorInfo> Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack<Value*> Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + int stackDepth_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), + stackDepth_(0), + features_(features), collectComments_() { +} + +bool OurReader::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); + + stackDepth_ = 0; + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + 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 OurReader::readValue() { + if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_; + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits<double>::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_; + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::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 '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else continue + 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': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + 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 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + 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 OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::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 OurReader::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 +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& tokenStart) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, 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 OurReader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *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 OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // 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; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast<Value::UInt>(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast<size_t>(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } else { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast<size_t>(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 OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + 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 OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int 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); + } + ret_unicode = static_cast<unsigned int>(unicode); + return true; +} + +bool +OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = 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 OurReader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::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; +} + +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_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::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { + std::vector<OurReader::StructuredError> allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { + return !errors_.size(); +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set<JSONCPP_STRING> valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) +{ + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_STRING doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// 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() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - 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 +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +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 2011 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 <json/assertions.h> +#include <json/value.h> +#include <json/writer.h> +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <math.h> +#include <sstream> +#include <utility> +#include <cstring> +#include <cassert> +#ifdef JSON_USE_CPPTL +#include <cpptl/conststring.h> +#endif +#include <cstddef> // size_t +#include <algorithm> // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +//const unsigned char& kNullRef = kNull[0]; +//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); +//const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() +{ + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but DO NOT +// use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + //return d >= static_cast<double>(min) && d <= static_cast<double>(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1)); +} + +template <typename T> static inline double integerToDouble(T value) { + return static_cast<double>(value); +} + +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** 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, + size_t length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast<size_t>(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast<char*>(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U; + char* newString = static_cast<char*>(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast<unsigned*>(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast<unsigned>(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast<unsigned const*>(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length==0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + free(value); +} +static inline void releaseStringValue(char* value, unsigned) { + free(value); +} +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(JSONCPP_STRING const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +LogicError::LogicError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) +{} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_, 0u); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = static_cast<unsigned>(other.cstr_ + ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(CZString other) { + swap(other); + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// 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 vtype) { + static char const empty[] = ""; + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast<char*>(static_cast<char const*>(empty)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); +} + +Value::Value(const JSONCPP_STRING& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast<char*>(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0), start_(other.start_), limit_(other.limit_) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + 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_, strlen(otherComment.comment_)); + } + } +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + delete[] comments_; + + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(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 & 0x1; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +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: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + 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_); + } + 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: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +JSONCPP_STRING Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return JSONCPP_STRING(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#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 intValue: + return static_cast<double>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<double>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast<float>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<float>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast<float>(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast<float>(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString() == "") || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// 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; + 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()); + } + 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_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + 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); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + 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, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(cend-key), 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, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullSingleton(); + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_STRING& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullSingleton(); + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const JSONCPP_STRING& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(JSONCPP_STRING const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(JSONCPP_STRING((*it).first.data(), + (*it).first.length())); + } + 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<const CZString &>() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type<const Value &>() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif +} + +bool Value::isDouble() const { return type_ == realValue || isIntegral(); } + +bool Value::isNumeric() const { return isIntegral() || isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { + StyledWriter writer; + return writer.write(*this); +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_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 JSONCPP_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 == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_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 JSONCPP_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... + return Value::null; + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + 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::nullSingleton()) + 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 2011 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 <json/writer.h> +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <iomanip> +#include <memory> +#include <sstream> +#include <utility> +#include <set> +#include <cassert> +#include <cstring> +#include <cstdio> + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include <float.h> +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) +#include <ieeefp.h> +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include <math.h> +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include <math.h> +#define isfinite finite +#endif +#endif +#else +#include <cmath> +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__BORLANDC__) +#include <float.h> +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<StreamWriter> StreamWriterPtr; +#else +typedef std::auto_ptr<StreamWriter> StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} +} + +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +JSONCPP_STRING valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + JSONCPP_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 </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if (isControlCharacter(*c)) { + JSONCPP_OSTRINGSTREAM oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++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 </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if ((isControlCharacter(*c)) || (*c == 0)) { + JSONCPP_OSTRINGSTREAM oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + 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: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex 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 JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_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: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 JSONCPP_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) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_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 JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + 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: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 JSONCPP_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 { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + 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) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +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; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set<JSONCPP_STRING> valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/LICENSE b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ad76b1da84b4677aadb4b64b235659081f2f3154 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/LICENSE @@ -0,0 +1,31 @@ + +Copyright (c) 2000-2017 Chih-Chung Chang and Chih-Jen Lin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither name of copyright holders nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/libsvm.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/libsvm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77ea425b8b36460b69c43fc76dac3b99e527e557 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/libsvm.cpp @@ -0,0 +1,3184 @@ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <float.h> +#include <string.h> +#include <stdarg.h> +#include <limits.h> +#include <locale.h> +#include "libsvm.h" + +namespace LIBSVM { + int libsvm_version = LIBSVM_VERSION; + typedef float Qfloat; + typedef signed char schar; +#ifndef min + template <class T> static inline T min(T x,T y) { return (x<y)?x:y; } +#endif +#ifndef max + template <class T> static inline T max(T x,T y) { return (x>y)?x:y; } +#endif + template <class T> static inline void swap(T& x, T& y) { T t=x; x=y; y=t; } + template <class S, class T> static inline void clone(T*& dst, S* src, int n) + { + dst = new T[n]; + memcpy((void *)dst,(void *)src,sizeof(T)*n); + } + static inline double powi(double base, int times) + { + double tmp = base, ret = 1.0; + + for(int t=times; t>0; t/=2) + { + if(t%2==1) ret*=tmp; + tmp = tmp * tmp; + } + return ret; + } +#define INF HUGE_VAL +#define TAU 1e-12 +#define Malloc(type,n) (type *)malloc((n)*sizeof(type)) + + static void print_string_stdout(const char *s) + { + fputs(s,stdout); + fflush(stdout); + } + static void (*svm_print_string) (const char *) = &print_string_stdout; +#if 1 + static void info(const char *fmt,...) + { + char buf[BUFSIZ]; + va_list ap; + va_start(ap,fmt); + vsprintf(buf,fmt,ap); + va_end(ap); + (*svm_print_string)(buf); + } +#else + static void info(const char *fmt,...) {} +#endif + + // + // Kernel Cache + // + // l is the number of total data items + // size is the cache size limit in bytes + // + class Cache + { + public: + Cache(int l,long int size); + ~Cache(); + + // request data [0,len) + // return some position p where [p,len) need to be filled + // (p >= len if nothing needs to be filled) + int get_data(const int index, Qfloat **data, int len); + void swap_index(int i, int j); + private: + int l; + long int size; + struct head_t + { + head_t *prev, *next; // a circular list + Qfloat *data; + int len; // data[0,len) is cached in this entry + }; + + head_t *head; + head_t lru_head; + void lru_delete(head_t *h); + void lru_insert(head_t *h); + }; + + Cache::Cache(int l_,long int size_):l(l_),size(size_) + { + head = (head_t *)calloc(l,sizeof(head_t)); // initialized to 0 + size /= sizeof(Qfloat); + size -= l * sizeof(head_t) / sizeof(Qfloat); + size = max(size, 2 * (long int) l); // cache must be large enough for two columns + lru_head.next = lru_head.prev = &lru_head; + } + + Cache::~Cache() + { + for(head_t *h = lru_head.next; h != &lru_head; h=h->next) + free(h->data); + free(head); + } + + void Cache::lru_delete(head_t *h) + { + // delete from current location + h->prev->next = h->next; + h->next->prev = h->prev; + } + + void Cache::lru_insert(head_t *h) + { + // insert to last position + h->next = &lru_head; + h->prev = lru_head.prev; + h->prev->next = h; + h->next->prev = h; + } + + int Cache::get_data(const int index, Qfloat **data, int len) + { + head_t *h = &head[index]; + if(h->len) lru_delete(h); + int more = len - h->len; + + if(more > 0) + { + // free old space + while(size < more) + { + head_t *old = lru_head.next; + lru_delete(old); + free(old->data); + size += old->len; + old->data = 0; + old->len = 0; + } + + // allocate new space + h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len); + size -= more; + swap(h->len,len); + } + + lru_insert(h); + *data = h->data; + return len; + } + + void Cache::swap_index(int i, int j) + { + if(i==j) return; + + if(head[i].len) lru_delete(&head[i]); + if(head[j].len) lru_delete(&head[j]); + swap(head[i].data,head[j].data); + swap(head[i].len,head[j].len); + if(head[i].len) lru_insert(&head[i]); + if(head[j].len) lru_insert(&head[j]); + + if(i>j) swap(i,j); + for(head_t *h = lru_head.next; h!=&lru_head; h=h->next) + { + if(h->len > i) + { + if(h->len > j) + swap(h->data[i],h->data[j]); + else + { + // give up + lru_delete(h); + free(h->data); + size += h->len; + h->data = 0; + h->len = 0; + } + } + } + } + + // + // Kernel evaluation + // + // the static method k_function is for doing single kernel evaluation + // the constructor of Kernel prepares to calculate the l*l kernel matrix + // the member function get_Q is for getting one column from the Q Matrix + // + class QMatrix { + public: + virtual Qfloat *get_Q(int column, int len) const = 0; + virtual double *get_QD() const = 0; + virtual void swap_index(int i, int j) const = 0; + virtual ~QMatrix() {} + }; + + class Kernel: public QMatrix { + public: + Kernel(int l, svm_node * const * x, const svm_parameter& param); + virtual ~Kernel(); + + static double k_function(const svm_node *x, const svm_node *y, + const svm_parameter& param); + virtual Qfloat *get_Q(int column, int len) const = 0; + virtual double *get_QD() const = 0; + virtual void swap_index(int i, int j) const // no so const... + { + swap(x[i],x[j]); + if(x_square) swap(x_square[i],x_square[j]); + } + protected: + + double (Kernel::*kernel_function)(int i, int j) const; + + private: + const svm_node **x; + double *x_square; + + // svm_parameter + const int kernel_type; + const int degree; + const double gamma; + const double coef0; + + static double dot(const svm_node *px, const svm_node *py); + double kernel_linear(int i, int j) const + { + return dot(x[i],x[j]); + } + double kernel_poly(int i, int j) const + { + return powi(gamma*dot(x[i],x[j])+coef0,degree); + } + double kernel_rbf(int i, int j) const + { + return exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j]))); + } + double kernel_sigmoid(int i, int j) const + { + return tanh(gamma*dot(x[i],x[j])+coef0); + } + double kernel_precomputed(int i, int j) const + { + return x[i][(int)(x[j][0].value)].value; + } + }; + + Kernel::Kernel(int l, svm_node * const * x_, const svm_parameter& param) + :kernel_type(param.kernel_type), degree(param.degree), + gamma(param.gamma), coef0(param.coef0) + { + switch(kernel_type) + { + case LINEAR: + kernel_function = &Kernel::kernel_linear; + break; + case POLY: + kernel_function = &Kernel::kernel_poly; + break; + case RBF: + kernel_function = &Kernel::kernel_rbf; + break; + case SIGMOID: + kernel_function = &Kernel::kernel_sigmoid; + break; + case PRECOMPUTED: + kernel_function = &Kernel::kernel_precomputed; + break; + } + + clone(x,x_,l); + + if(kernel_type == RBF) + { + x_square = new double[l]; + for(int i=0;i<l;i++) + x_square[i] = dot(x[i],x[i]); + } + else + x_square = 0; + } + + Kernel::~Kernel() + { + delete[] x; + delete[] x_square; + } + + double Kernel::dot(const svm_node *px, const svm_node *py) + { + double sum = 0; + while(px->index != -1 && py->index != -1) + { + if(px->index == py->index) + { + sum += px->value * py->value; + ++px; + ++py; + } + else + { + if(px->index > py->index) + ++py; + else + ++px; + } + } + return sum; + } + + double Kernel::k_function(const svm_node *x, const svm_node *y, + const svm_parameter& param) + { + switch(param.kernel_type) + { + case LINEAR: + return dot(x,y); + case POLY: + return powi(param.gamma*dot(x,y)+param.coef0,param.degree); + case RBF: + { + double sum = 0; + while(x->index != -1 && y->index !=-1) + { + if(x->index == y->index) + { + double d = x->value - y->value; + sum += d*d; + ++x; + ++y; + } + else + { + if(x->index > y->index) + { + sum += y->value * y->value; + ++y; + } + else + { + sum += x->value * x->value; + ++x; + } + } + } + + while(x->index != -1) + { + sum += x->value * x->value; + ++x; + } + + while(y->index != -1) + { + sum += y->value * y->value; + ++y; + } + + return exp(-param.gamma*sum); + } + case SIGMOID: + return tanh(param.gamma*dot(x,y)+param.coef0); + case PRECOMPUTED: //x: test (validation), y: SV + return x[(int)(y->value)].value; + default: + return 0; // Unreachable + } + } + + // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918 + // Solves: + // + // min 0.5(\alpha^T Q \alpha) + p^T \alpha + // + // y^T \alpha = \delta + // y_i = +1 or -1 + // 0 <= alpha_i <= Cp for y_i = 1 + // 0 <= alpha_i <= Cn for y_i = -1 + // + // Given: + // + // Q, p, y, Cp, Cn, and an initial feasible point \alpha + // l is the size of vectors and matrices + // eps is the stopping tolerance + // + // solution will be put in \alpha, objective value will be put in obj + // + class Solver { + public: + Solver() {}; + virtual ~Solver() {}; + + struct SolutionInfo { + double obj; + double rho; + double upper_bound_p; + double upper_bound_n; + double r; // for Solver_NU + }; + + void Solve(int l, const QMatrix& Q, const double *p_, const schar *y_, + double *alpha_, double Cp, double Cn, double eps, + SolutionInfo* si, int shrinking); + protected: + int active_size; + schar *y; + double *G; // gradient of objective function + enum { LOWER_BOUND, UPPER_BOUND, FREE }; + char *alpha_status; // LOWER_BOUND, UPPER_BOUND, FREE + double *alpha; + const QMatrix *Q; + const double *QD; + double eps; + double Cp,Cn; + double *p; + int *active_set; + double *G_bar; // gradient, if we treat free variables as 0 + int l; + bool unshrink; // XXX + + double get_C(int i) + { + return (y[i] > 0)? Cp : Cn; + } + void update_alpha_status(int i) + { + if(alpha[i] >= get_C(i)) + alpha_status[i] = UPPER_BOUND; + else if(alpha[i] <= 0) + alpha_status[i] = LOWER_BOUND; + else alpha_status[i] = FREE; + } + bool is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; } + bool is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; } + bool is_free(int i) { return alpha_status[i] == FREE; } + void swap_index(int i, int j); + void reconstruct_gradient(); + virtual int select_working_set(int &i, int &j); + virtual double calculate_rho(); + virtual void do_shrinking(); + private: + bool be_shrunk(int i, double Gmax1, double Gmax2); + }; + + void Solver::swap_index(int i, int j) + { + Q->swap_index(i,j); + swap(y[i],y[j]); + swap(G[i],G[j]); + swap(alpha_status[i],alpha_status[j]); + swap(alpha[i],alpha[j]); + swap(p[i],p[j]); + swap(active_set[i],active_set[j]); + swap(G_bar[i],G_bar[j]); + } + + void Solver::reconstruct_gradient() + { + // reconstruct inactive elements of G from G_bar and free variables + + if(active_size == l) return; + + int i,j; + int nr_free = 0; + + for(j=active_size;j<l;j++) + G[j] = G_bar[j] + p[j]; + + for(j=0;j<active_size;j++) + if(is_free(j)) + nr_free++; + + if(2*nr_free < active_size) + info("\nWARNING: using -h 0 may be faster\n"); + + if (nr_free*l > 2*active_size*(l-active_size)) + { + for(i=active_size;i<l;i++) + { + const Qfloat *Q_i = Q->get_Q(i,active_size); + for(j=0;j<active_size;j++) + if(is_free(j)) + G[i] += alpha[j] * Q_i[j]; + } + } + else + { + for(i=0;i<active_size;i++) + if(is_free(i)) + { + const Qfloat *Q_i = Q->get_Q(i,l); + double alpha_i = alpha[i]; + for(j=active_size;j<l;j++) + G[j] += alpha_i * Q_i[j]; + } + } + } + + void Solver::Solve(int l, const QMatrix& Q, const double *p_, const schar *y_, + double *alpha_, double Cp, double Cn, double eps, + SolutionInfo* si, int shrinking) + { + this->l = l; + this->Q = &Q; + QD=Q.get_QD(); + clone(p, p_,l); + clone(y, y_,l); + clone(alpha,alpha_,l); + this->Cp = Cp; + this->Cn = Cn; + this->eps = eps; + unshrink = false; + + // initialize alpha_status + { + alpha_status = new char[l]; + for(int i=0;i<l;i++) + update_alpha_status(i); + } + + // initialize active set (for shrinking) + { + active_set = new int[l]; + for(int i=0;i<l;i++) + active_set[i] = i; + active_size = l; + } + + // initialize gradient + { + G = new double[l]; + G_bar = new double[l]; + int i; + for(i=0;i<l;i++) + { + G[i] = p[i]; + G_bar[i] = 0; + } + for(i=0;i<l;i++) + if(!is_lower_bound(i)) + { + const Qfloat *Q_i = Q.get_Q(i,l); + double alpha_i = alpha[i]; + int j; + for(j=0;j<l;j++) + G[j] += alpha_i*Q_i[j]; + if(is_upper_bound(i)) + for(j=0;j<l;j++) + G_bar[j] += get_C(i) * Q_i[j]; + } + } + + // optimization step + + int iter = 0; + int max_iter = max(10000000, l>INT_MAX/100 ? INT_MAX : 100*l); + int counter = min(l,1000)+1; + + while(iter < max_iter) + { + // show progress and do shrinking + + if(--counter == 0) + { + counter = min(l,1000); + if(shrinking) do_shrinking(); + info("."); + } + + int i,j; + if(select_working_set(i,j)!=0) + { + // reconstruct the whole gradient + reconstruct_gradient(); + // reset active set size and check + active_size = l; + info("*"); + if(select_working_set(i,j)!=0) + break; + else + counter = 1; // do shrinking next iteration + } + + ++iter; + + // update alpha[i] and alpha[j], handle bounds carefully + + const Qfloat *Q_i = Q.get_Q(i,active_size); + const Qfloat *Q_j = Q.get_Q(j,active_size); + + double C_i = get_C(i); + double C_j = get_C(j); + + double old_alpha_i = alpha[i]; + double old_alpha_j = alpha[j]; + + if(y[i]!=y[j]) + { + double quad_coef = QD[i]+QD[j]+2*Q_i[j]; + if (quad_coef <= 0) + quad_coef = TAU; + double delta = (-G[i]-G[j])/quad_coef; + double diff = alpha[i] - alpha[j]; + alpha[i] += delta; + alpha[j] += delta; + + if(diff > 0) + { + if(alpha[j] < 0) + { + alpha[j] = 0; + alpha[i] = diff; + } + } + else + { + if(alpha[i] < 0) + { + alpha[i] = 0; + alpha[j] = -diff; + } + } + if(diff > C_i - C_j) + { + if(alpha[i] > C_i) + { + alpha[i] = C_i; + alpha[j] = C_i - diff; + } + } + else + { + if(alpha[j] > C_j) + { + alpha[j] = C_j; + alpha[i] = C_j + diff; + } + } + } + else + { + double quad_coef = QD[i]+QD[j]-2*Q_i[j]; + if (quad_coef <= 0) + quad_coef = TAU; + double delta = (G[i]-G[j])/quad_coef; + double sum = alpha[i] + alpha[j]; + alpha[i] -= delta; + alpha[j] += delta; + + if(sum > C_i) + { + if(alpha[i] > C_i) + { + alpha[i] = C_i; + alpha[j] = sum - C_i; + } + } + else + { + if(alpha[j] < 0) + { + alpha[j] = 0; + alpha[i] = sum; + } + } + if(sum > C_j) + { + if(alpha[j] > C_j) + { + alpha[j] = C_j; + alpha[i] = sum - C_j; + } + } + else + { + if(alpha[i] < 0) + { + alpha[i] = 0; + alpha[j] = sum; + } + } + } + + // update G + + double delta_alpha_i = alpha[i] - old_alpha_i; + double delta_alpha_j = alpha[j] - old_alpha_j; + + for(int k=0;k<active_size;k++) + { + G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j; + } + + // update alpha_status and G_bar + + { + bool ui = is_upper_bound(i); + bool uj = is_upper_bound(j); + update_alpha_status(i); + update_alpha_status(j); + int k; + if(ui != is_upper_bound(i)) + { + Q_i = Q.get_Q(i,l); + if(ui) + for(k=0;k<l;k++) + G_bar[k] -= C_i * Q_i[k]; + else + for(k=0;k<l;k++) + G_bar[k] += C_i * Q_i[k]; + } + + if(uj != is_upper_bound(j)) + { + Q_j = Q.get_Q(j,l); + if(uj) + for(k=0;k<l;k++) + G_bar[k] -= C_j * Q_j[k]; + else + for(k=0;k<l;k++) + G_bar[k] += C_j * Q_j[k]; + } + } + } + + if(iter >= max_iter) + { + if(active_size < l) + { + // reconstruct the whole gradient to calculate objective value + reconstruct_gradient(); + active_size = l; + info("*"); + } + fprintf(stderr,"\nWARNING: reaching max number of iterations\n"); + } + + // calculate rho + + si->rho = calculate_rho(); + + // calculate objective value + { + double v = 0; + int i; + for(i=0;i<l;i++) + v += alpha[i] * (G[i] + p[i]); + + si->obj = v/2; + } + + // put back the solution + { + for(int i=0;i<l;i++) + alpha_[active_set[i]] = alpha[i]; + } + + // juggle everything back + /*{ + for(int i=0;i<l;i++) + while(active_set[i] != i) + swap_index(i,active_set[i]); + // or Q.swap_index(i,active_set[i]); + }*/ + + si->upper_bound_p = Cp; + si->upper_bound_n = Cn; + + info("\noptimization finished, #iter = %d\n",iter); + + delete[] p; + delete[] y; + delete[] alpha; + delete[] alpha_status; + delete[] active_set; + delete[] G; + delete[] G_bar; + } + + // return 1 if already optimal, return 0 otherwise + int Solver::select_working_set(int &out_i, int &out_j) + { + // return i,j such that + // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) + // j: minimizes the decrease of obj value + // (if quadratic coefficeint <= 0, replace it with tau) + // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) + + double Gmax = -INF; + double Gmax2 = -INF; + int Gmax_idx = -1; + int Gmin_idx = -1; + double obj_diff_min = INF; + + for(int t=0;t<active_size;t++) + if(y[t]==+1) + { + if(!is_upper_bound(t)) + if(-G[t] >= Gmax) + { + Gmax = -G[t]; + Gmax_idx = t; + } + } + else + { + if(!is_lower_bound(t)) + if(G[t] >= Gmax) + { + Gmax = G[t]; + Gmax_idx = t; + } + } + + int i = Gmax_idx; + const Qfloat *Q_i = NULL; + if(i != -1) // NULL Q_i not accessed: Gmax=-INF if i=-1 + Q_i = Q->get_Q(i,active_size); + + for(int j=0;j<active_size;j++) + { + if(y[j]==+1) + { + if (!is_lower_bound(j)) + { + double grad_diff=Gmax+G[j]; + if (G[j] >= Gmax2) + Gmax2 = G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + else + { + if (!is_upper_bound(j)) + { + double grad_diff= Gmax-G[j]; + if (-G[j] >= Gmax2) + Gmax2 = -G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + } + + if(Gmax+Gmax2 < eps || Gmin_idx == -1) + return 1; + + out_i = Gmax_idx; + out_j = Gmin_idx; + return 0; + } + + bool Solver::be_shrunk(int i, double Gmax1, double Gmax2) + { + if(is_upper_bound(i)) + { + if(y[i]==+1) + return(-G[i] > Gmax1); + else + return(-G[i] > Gmax2); + } + else if(is_lower_bound(i)) + { + if(y[i]==+1) + return(G[i] > Gmax2); + else + return(G[i] > Gmax1); + } + else + return(false); + } + + void Solver::do_shrinking() + { + int i; + double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) } + double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) } + + // find maximal violating pair first + for(i=0;i<active_size;i++) + { + if(y[i]==+1) + { + if(!is_upper_bound(i)) + { + if(-G[i] >= Gmax1) + Gmax1 = -G[i]; + } + if(!is_lower_bound(i)) + { + if(G[i] >= Gmax2) + Gmax2 = G[i]; + } + } + else + { + if(!is_upper_bound(i)) + { + if(-G[i] >= Gmax2) + Gmax2 = -G[i]; + } + if(!is_lower_bound(i)) + { + if(G[i] >= Gmax1) + Gmax1 = G[i]; + } + } + } + + if(unshrink == false && Gmax1 + Gmax2 <= eps*10) + { + unshrink = true; + reconstruct_gradient(); + active_size = l; + info("*"); + } + + for(i=0;i<active_size;i++) + if (be_shrunk(i, Gmax1, Gmax2)) + { + active_size--; + while (active_size > i) + { + if (!be_shrunk(active_size, Gmax1, Gmax2)) + { + swap_index(i,active_size); + break; + } + active_size--; + } + } + } + + double Solver::calculate_rho() + { + double r; + int nr_free = 0; + double ub = INF, lb = -INF, sum_free = 0; + for(int i=0;i<active_size;i++) + { + double yG = y[i]*G[i]; + + if(is_upper_bound(i)) + { + if(y[i]==-1) + ub = min(ub,yG); + else + lb = max(lb,yG); + } + else if(is_lower_bound(i)) + { + if(y[i]==+1) + ub = min(ub,yG); + else + lb = max(lb,yG); + } + else + { + ++nr_free; + sum_free += yG; + } + } + + if(nr_free>0) + r = sum_free/nr_free; + else + r = (ub+lb)/2; + + return r; + } + + // + // Solver for nu-svm classification and regression + // + // additional constraint: e^T \alpha = constant + // + class Solver_NU: public Solver + { + public: + Solver_NU() {} + void Solve(int l, const QMatrix& Q, const double *p, const schar *y, + double *alpha, double Cp, double Cn, double eps, + SolutionInfo* si, int shrinking) + { + this->si = si; + Solver::Solve(l,Q,p,y,alpha,Cp,Cn,eps,si,shrinking); + } + private: + SolutionInfo *si; + int select_working_set(int &i, int &j); + double calculate_rho(); + bool be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4); + void do_shrinking(); + }; + + // return 1 if already optimal, return 0 otherwise + int Solver_NU::select_working_set(int &out_i, int &out_j) + { + // return i,j such that y_i = y_j and + // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) + // j: minimizes the decrease of obj value + // (if quadratic coefficeint <= 0, replace it with tau) + // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) + + double Gmaxp = -INF; + double Gmaxp2 = -INF; + int Gmaxp_idx = -1; + + double Gmaxn = -INF; + double Gmaxn2 = -INF; + int Gmaxn_idx = -1; + + int Gmin_idx = -1; + double obj_diff_min = INF; + + for(int t=0;t<active_size;t++) + if(y[t]==+1) + { + if(!is_upper_bound(t)) + if(-G[t] >= Gmaxp) + { + Gmaxp = -G[t]; + Gmaxp_idx = t; + } + } + else + { + if(!is_lower_bound(t)) + if(G[t] >= Gmaxn) + { + Gmaxn = G[t]; + Gmaxn_idx = t; + } + } + + int ip = Gmaxp_idx; + int in = Gmaxn_idx; + const Qfloat *Q_ip = NULL; + const Qfloat *Q_in = NULL; + if(ip != -1) // NULL Q_ip not accessed: Gmaxp=-INF if ip=-1 + Q_ip = Q->get_Q(ip,active_size); + if(in != -1) + Q_in = Q->get_Q(in,active_size); + + for(int j=0;j<active_size;j++) + { + if(y[j]==+1) + { + if (!is_lower_bound(j)) + { + double grad_diff=Gmaxp+G[j]; + if (G[j] >= Gmaxp2) + Gmaxp2 = G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[ip]+QD[j]-2*Q_ip[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + else + { + if (!is_upper_bound(j)) + { + double grad_diff=Gmaxn-G[j]; + if (-G[j] >= Gmaxn2) + Gmaxn2 = -G[j]; + if (grad_diff > 0) + { + double obj_diff; + double quad_coef = QD[in]+QD[j]-2*Q_in[j]; + if (quad_coef > 0) + obj_diff = -(grad_diff*grad_diff)/quad_coef; + else + obj_diff = -(grad_diff*grad_diff)/TAU; + + if (obj_diff <= obj_diff_min) + { + Gmin_idx=j; + obj_diff_min = obj_diff; + } + } + } + } + } + + if(max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps || Gmin_idx == -1) + return 1; + + if (y[Gmin_idx] == +1) + out_i = Gmaxp_idx; + else + out_i = Gmaxn_idx; + out_j = Gmin_idx; + + return 0; + } + + bool Solver_NU::be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4) + { + if(is_upper_bound(i)) + { + if(y[i]==+1) + return(-G[i] > Gmax1); + else + return(-G[i] > Gmax4); + } + else if(is_lower_bound(i)) + { + if(y[i]==+1) + return(G[i] > Gmax2); + else + return(G[i] > Gmax3); + } + else + return(false); + } + + void Solver_NU::do_shrinking() + { + double Gmax1 = -INF; // max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) } + double Gmax2 = -INF; // max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) } + double Gmax3 = -INF; // max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) } + double Gmax4 = -INF; // max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) } + + // find maximal violating pair first + int i; + for(i=0;i<active_size;i++) + { + if(!is_upper_bound(i)) + { + if(y[i]==+1) + { + if(-G[i] > Gmax1) Gmax1 = -G[i]; + } + else if(-G[i] > Gmax4) Gmax4 = -G[i]; + } + if(!is_lower_bound(i)) + { + if(y[i]==+1) + { + if(G[i] > Gmax2) Gmax2 = G[i]; + } + else if(G[i] > Gmax3) Gmax3 = G[i]; + } + } + + if(unshrink == false && max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10) + { + unshrink = true; + reconstruct_gradient(); + active_size = l; + } + + for(i=0;i<active_size;i++) + if (be_shrunk(i, Gmax1, Gmax2, Gmax3, Gmax4)) + { + active_size--; + while (active_size > i) + { + if (!be_shrunk(active_size, Gmax1, Gmax2, Gmax3, Gmax4)) + { + swap_index(i,active_size); + break; + } + active_size--; + } + } + } + + double Solver_NU::calculate_rho() + { + int nr_free1 = 0,nr_free2 = 0; + double ub1 = INF, ub2 = INF; + double lb1 = -INF, lb2 = -INF; + double sum_free1 = 0, sum_free2 = 0; + + for(int i=0;i<active_size;i++) + { + if(y[i]==+1) + { + if(is_upper_bound(i)) + lb1 = max(lb1,G[i]); + else if(is_lower_bound(i)) + ub1 = min(ub1,G[i]); + else + { + ++nr_free1; + sum_free1 += G[i]; + } + } + else + { + if(is_upper_bound(i)) + lb2 = max(lb2,G[i]); + else if(is_lower_bound(i)) + ub2 = min(ub2,G[i]); + else + { + ++nr_free2; + sum_free2 += G[i]; + } + } + } + + double r1,r2; + if(nr_free1 > 0) + r1 = sum_free1/nr_free1; + else + r1 = (ub1+lb1)/2; + + if(nr_free2 > 0) + r2 = sum_free2/nr_free2; + else + r2 = (ub2+lb2)/2; + + si->r = (r1+r2)/2; + return (r1-r2)/2; + } + + // + // Q matrices for various formulations + // + class SVC_Q: public Kernel + { + public: + SVC_Q(const svm_problem& prob, const svm_parameter& param, const schar *y_) + :Kernel(prob.l, prob.x, param) + { + clone(y,y_,prob.l); + cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20))); + QD = new double[prob.l]; + for(int i=0;i<prob.l;i++) + QD[i] = (this->*kernel_function)(i,i); + } + + Qfloat *get_Q(int i, int len) const + { + Qfloat *data; + int start, j; + if((start = cache->get_data(i,&data,len)) < len) + { + for(j=start;j<len;j++) + data[j] = (Qfloat)(y[i]*y[j]*(this->*kernel_function)(i,j)); + } + return data; + } + + double *get_QD() const + { + return QD; + } + + void swap_index(int i, int j) const + { + cache->swap_index(i,j); + Kernel::swap_index(i,j); + swap(y[i],y[j]); + swap(QD[i],QD[j]); + } + + ~SVC_Q() + { + delete[] y; + delete cache; + delete[] QD; + } + private: + schar *y; + Cache *cache; + double *QD; + }; + + class ONE_CLASS_Q: public Kernel + { + public: + ONE_CLASS_Q(const svm_problem& prob, const svm_parameter& param) + :Kernel(prob.l, prob.x, param) + { + cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20))); + QD = new double[prob.l]; + for(int i=0;i<prob.l;i++) + QD[i] = (this->*kernel_function)(i,i); + } + + Qfloat *get_Q(int i, int len) const + { + Qfloat *data; + int start, j; + if((start = cache->get_data(i,&data,len)) < len) + { + for(j=start;j<len;j++) + data[j] = (Qfloat)(this->*kernel_function)(i,j); + } + return data; + } + + double *get_QD() const + { + return QD; + } + + void swap_index(int i, int j) const + { + cache->swap_index(i,j); + Kernel::swap_index(i,j); + swap(QD[i],QD[j]); + } + + ~ONE_CLASS_Q() + { + delete cache; + delete[] QD; + } + private: + Cache *cache; + double *QD; + }; + + class SVR_Q: public Kernel + { + public: + SVR_Q(const svm_problem& prob, const svm_parameter& param) + :Kernel(prob.l, prob.x, param) + { + l = prob.l; + cache = new Cache(l,(long int)(param.cache_size*(1<<20))); + QD = new double[2*l]; + sign = new schar[2*l]; + index = new int[2*l]; + for(int k=0;k<l;k++) + { + sign[k] = 1; + sign[k+l] = -1; + index[k] = k; + index[k+l] = k; + QD[k] = (this->*kernel_function)(k,k); + QD[k+l] = QD[k]; + } + buffer[0] = new Qfloat[2*l]; + buffer[1] = new Qfloat[2*l]; + next_buffer = 0; + } + + void swap_index(int i, int j) const + { + swap(sign[i],sign[j]); + swap(index[i],index[j]); + swap(QD[i],QD[j]); + } + + Qfloat *get_Q(int i, int len) const + { + Qfloat *data; + int j, real_i = index[i]; + if(cache->get_data(real_i,&data,l) < l) + { + for(j=0;j<l;j++) + data[j] = (Qfloat)(this->*kernel_function)(real_i,j); + } + + // reorder and copy + Qfloat *buf = buffer[next_buffer]; + next_buffer = 1 - next_buffer; + schar si = sign[i]; + for(j=0;j<len;j++) + buf[j] = (Qfloat) si * (Qfloat) sign[j] * data[index[j]]; + return buf; + } + + double *get_QD() const + { + return QD; + } + + ~SVR_Q() + { + delete cache; + delete[] sign; + delete[] index; + delete[] buffer[0]; + delete[] buffer[1]; + delete[] QD; + } + private: + int l; + Cache *cache; + schar *sign; + int *index; + mutable int next_buffer; + Qfloat *buffer[2]; + double *QD; + }; + + // + // construct and solve various formulations + // + static void solve_c_svc( + const svm_problem *prob, const svm_parameter* param, + double *alpha, Solver::SolutionInfo* si, double Cp, double Cn) + { + int l = prob->l; + double *minus_ones = new double[l]; + schar *y = new schar[l]; + + int i; + + for(i=0;i<l;i++) + { + alpha[i] = 0; + minus_ones[i] = -1; + if(prob->y[i] > 0) y[i] = +1; else y[i] = -1; + } + + Solver s; + s.Solve(l, SVC_Q(*prob,*param,y), minus_ones, y, + alpha, Cp, Cn, param->eps, si, param->shrinking); + + double sum_alpha=0; + for(i=0;i<l;i++) + sum_alpha += alpha[i]; + + if (Cp==Cn) + info("nu = %f\n", sum_alpha/(Cp*prob->l)); + + for(i=0;i<l;i++) + alpha[i] *= y[i]; + + delete[] minus_ones; + delete[] y; + } + + static void solve_nu_svc( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int i; + int l = prob->l; + double nu = param->nu; + + schar *y = new schar[l]; + + for(i=0;i<l;i++) + if(prob->y[i]>0) + y[i] = +1; + else + y[i] = -1; + + double sum_pos = nu*l/2; + double sum_neg = nu*l/2; + + for(i=0;i<l;i++) + if(y[i] == +1) + { + alpha[i] = min(1.0,sum_pos); + sum_pos -= alpha[i]; + } + else + { + alpha[i] = min(1.0,sum_neg); + sum_neg -= alpha[i]; + } + + double *zeros = new double[l]; + + for(i=0;i<l;i++) + zeros[i] = 0; + + Solver_NU s; + s.Solve(l, SVC_Q(*prob,*param,y), zeros, y, + alpha, 1.0, 1.0, param->eps, si, param->shrinking); + double r = si->r; + + info("C = %f\n",1/r); + + for(i=0;i<l;i++) + alpha[i] *= y[i]/r; + + si->rho /= r; + si->obj /= (r*r); + si->upper_bound_p = 1/r; + si->upper_bound_n = 1/r; + + delete[] y; + delete[] zeros; + } + + static void solve_one_class( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int l = prob->l; + double *zeros = new double[l]; + schar *ones = new schar[l]; + int i; + + int n = (int)(param->nu*prob->l); // # of alpha's at upper bound + + for(i=0;i<n;i++) + alpha[i] = 1; + if(n<prob->l) + alpha[n] = param->nu * prob->l - n; + for(i=n+1;i<l;i++) + alpha[i] = 0; + + for(i=0;i<l;i++) + { + zeros[i] = 0; + ones[i] = 1; + } + + Solver s; + s.Solve(l, ONE_CLASS_Q(*prob,*param), zeros, ones, + alpha, 1.0, 1.0, param->eps, si, param->shrinking); + + delete[] zeros; + delete[] ones; + } + + static void solve_epsilon_svr( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int l = prob->l; + double *alpha2 = new double[2*l]; + double *linear_term = new double[2*l]; + schar *y = new schar[2*l]; + int i; + + for(i=0;i<l;i++) + { + alpha2[i] = 0; + linear_term[i] = param->p - prob->y[i]; + y[i] = 1; + + alpha2[i+l] = 0; + linear_term[i+l] = param->p + prob->y[i]; + y[i+l] = -1; + } + + Solver s; + s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y, + alpha2, param->C, param->C, param->eps, si, param->shrinking); + + double sum_alpha = 0; + for(i=0;i<l;i++) + { + alpha[i] = alpha2[i] - alpha2[i+l]; + sum_alpha += fabs(alpha[i]); + } + info("nu = %f\n",sum_alpha/(param->C*l)); + + delete[] alpha2; + delete[] linear_term; + delete[] y; + } + + static void solve_nu_svr( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) + { + int l = prob->l; + double C = param->C; + double *alpha2 = new double[2*l]; + double *linear_term = new double[2*l]; + schar *y = new schar[2*l]; + int i; + + double sum = C * param->nu * l / 2; + for(i=0;i<l;i++) + { + alpha2[i] = alpha2[i+l] = min(sum,C); + sum -= alpha2[i]; + + linear_term[i] = - prob->y[i]; + y[i] = 1; + + linear_term[i+l] = prob->y[i]; + y[i+l] = -1; + } + + Solver_NU s; + s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y, + alpha2, C, C, param->eps, si, param->shrinking); + + info("epsilon = %f\n",-si->r); + + for(i=0;i<l;i++) + alpha[i] = alpha2[i] - alpha2[i+l]; + + delete[] alpha2; + delete[] linear_term; + delete[] y; + } + + // + // decision_function + // + struct decision_function + { + double *alpha; + double rho; + }; + + static decision_function svm_train_one( + const svm_problem *prob, const svm_parameter *param, + double Cp, double Cn) + { + double *alpha = Malloc(double,prob->l); + Solver::SolutionInfo si; + switch(param->svm_type) + { + case C_SVC: + solve_c_svc(prob,param,alpha,&si,Cp,Cn); + break; + case NU_SVC: + solve_nu_svc(prob,param,alpha,&si); + break; + case ONE_CLASS: + solve_one_class(prob,param,alpha,&si); + break; + case EPSILON_SVR: + solve_epsilon_svr(prob,param,alpha,&si); + break; + case NU_SVR: + solve_nu_svr(prob,param,alpha,&si); + break; + } + + info("obj = %f, rho = %f\n",si.obj,si.rho); + + // output SVs + + int nSV = 0; + int nBSV = 0; + for(int i=0;i<prob->l;i++) + { + if(fabs(alpha[i]) > 0) + { + ++nSV; + if(prob->y[i] > 0) + { + if(fabs(alpha[i]) >= si.upper_bound_p) + ++nBSV; + } + else + { + if(fabs(alpha[i]) >= si.upper_bound_n) + ++nBSV; + } + } + } + + info("nSV = %d, nBSV = %d\n",nSV,nBSV); + + decision_function f; + f.alpha = alpha; + f.rho = si.rho; + return f; + } + + // Platt's binary SVM Probablistic Output: an improvement from Lin et al. + static void sigmoid_train( + int l, const double *dec_values, const double *labels, + double& A, double& B) + { + double prior1=0, prior0 = 0; + int i; + + for (i=0;i<l;i++) + if (labels[i] > 0) prior1+=1; + else prior0+=1; + + int max_iter=100; // Maximal number of iterations + double min_step=1e-10; // Minimal step taken in line search + double sigma=1e-12; // For numerically strict PD of Hessian + double eps=1e-5; + double hiTarget=(prior1+1.0)/(prior1+2.0); + double loTarget=1/(prior0+2.0); + double *t=Malloc(double,l); + double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize; + double newA,newB,newf,d1,d2; + int iter; + + // Initial Point and Initial Fun Value + A=0.0; B=log((prior0+1.0)/(prior1+1.0)); + double fval = 0.0; + + for (i=0;i<l;i++) + { + if (labels[i]>0) t[i]=hiTarget; + else t[i]=loTarget; + fApB = dec_values[i]*A+B; + if (fApB>=0) + fval += t[i]*fApB + log(1+exp(-fApB)); + else + fval += (t[i] - 1)*fApB +log(1+exp(fApB)); + } + for (iter=0;iter<max_iter;iter++) + { + // Update Gradient and Hessian (use H' = H + sigma I) + h11=sigma; // numerically ensures strict PD + h22=sigma; + h21=0.0;g1=0.0;g2=0.0; + for (i=0;i<l;i++) + { + fApB = dec_values[i]*A+B; + if (fApB >= 0) + { + p=exp(-fApB)/(1.0+exp(-fApB)); + q=1.0/(1.0+exp(-fApB)); + } + else + { + p=1.0/(1.0+exp(fApB)); + q=exp(fApB)/(1.0+exp(fApB)); + } + d2=p*q; + h11+=dec_values[i]*dec_values[i]*d2; + h22+=d2; + h21+=dec_values[i]*d2; + d1=t[i]-p; + g1+=dec_values[i]*d1; + g2+=d1; + } + + // Stopping Criteria + if (fabs(g1)<eps && fabs(g2)<eps) + break; + + // Finding Newton direction: -inv(H') * g + det=h11*h22-h21*h21; + dA=-(h22*g1 - h21 * g2) / det; + dB=-(-h21*g1+ h11 * g2) / det; + gd=g1*dA+g2*dB; + + + stepsize = 1; // Line Search + while (stepsize >= min_step) + { + newA = A + stepsize * dA; + newB = B + stepsize * dB; + + // New function value + newf = 0.0; + for (i=0;i<l;i++) + { + fApB = dec_values[i]*newA+newB; + if (fApB >= 0) + newf += t[i]*fApB + log(1+exp(-fApB)); + else + newf += (t[i] - 1)*fApB +log(1+exp(fApB)); + } + // Check sufficient decrease + if (newf<fval+0.0001*stepsize*gd) + { + A=newA;B=newB;fval=newf; + break; + } + else + stepsize = stepsize / 2.0; + } + + if (stepsize < min_step) + { + info("Line search fails in two-class probability estimates\n"); + break; + } + } + + if (iter>=max_iter) + info("Reaching maximal iterations in two-class probability estimates\n"); + free(t); + } + + static double sigmoid_predict(double decision_value, double A, double B) + { + double fApB = decision_value*A+B; + // 1-p used later; avoid catastrophic cancellation + if (fApB >= 0) + return exp(-fApB)/(1.0+exp(-fApB)); + else + return 1.0/(1+exp(fApB)) ; + } + + // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng + static void multiclass_probability(int k, double **r, double *p) + { + int t,j; + int iter = 0, max_iter=max(100,k); + double **Q=Malloc(double *,k); + double *Qp=Malloc(double,k); + double pQp, eps=0.005/k; + + for (t=0;t<k;t++) + { + p[t]=1.0/k; // Valid if k = 1 + Q[t]=Malloc(double,k); + Q[t][t]=0; + for (j=0;j<t;j++) + { + Q[t][t]+=r[j][t]*r[j][t]; + Q[t][j]=Q[j][t]; + } + for (j=t+1;j<k;j++) + { + Q[t][t]+=r[j][t]*r[j][t]; + Q[t][j]=-r[j][t]*r[t][j]; + } + } + for (iter=0;iter<max_iter;iter++) + { + // stopping condition, recalculate QP,pQP for numerical accuracy + pQp=0; + for (t=0;t<k;t++) + { + Qp[t]=0; + for (j=0;j<k;j++) + Qp[t]+=Q[t][j]*p[j]; + pQp+=p[t]*Qp[t]; + } + double max_error=0; + for (t=0;t<k;t++) + { + double error=fabs(Qp[t]-pQp); + if (error>max_error) + max_error=error; + } + if (max_error<eps) break; + + for (t=0;t<k;t++) + { + double diff=(-Qp[t]+pQp)/Q[t][t]; + p[t]+=diff; + pQp=(pQp+diff*(diff*Q[t][t]+2*Qp[t]))/(1+diff)/(1+diff); + for (j=0;j<k;j++) + { + Qp[j]=(Qp[j]+diff*Q[t][j])/(1+diff); + p[j]/=(1+diff); + } + } + } + if (iter>=max_iter) + info("Exceeds max_iter in multiclass_prob\n"); + for(t=0;t<k;t++) free(Q[t]); + free(Q); + free(Qp); + } + + // Cross-validation decision values for probability estimates + static void svm_binary_svc_probability( + const svm_problem *prob, const svm_parameter *param, + double Cp, double Cn, double& probA, double& probB) + { + int i; + int nr_fold = 5; + int *perm = Malloc(int,prob->l); + double *dec_values = Malloc(double,prob->l); + + // random shuffle + for(i=0;i<prob->l;i++) perm[i]=i; + for(i=0;i<prob->l;i++) + { + int j = i+rand()%(prob->l-i); + swap(perm[i],perm[j]); + } + for(i=0;i<nr_fold;i++) + { + int begin = i*prob->l/nr_fold; + int end = (i+1)*prob->l/nr_fold; + int j,k; + struct svm_problem subprob; + + subprob.l = prob->l-(end-begin); + subprob.x = Malloc(struct svm_node*,subprob.l); + subprob.y = Malloc(double,subprob.l); + + k=0; + for(j=0;j<begin;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + for(j=end;j<prob->l;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + int p_count=0,n_count=0; + for(j=0;j<k;j++) + if(subprob.y[j]>0) + p_count++; + else + n_count++; + + if(p_count==0 && n_count==0) + for(j=begin;j<end;j++) + dec_values[perm[j]] = 0; + else if(p_count > 0 && n_count == 0) + for(j=begin;j<end;j++) + dec_values[perm[j]] = 1; + else if(p_count == 0 && n_count > 0) + for(j=begin;j<end;j++) + dec_values[perm[j]] = -1; + else + { + svm_parameter subparam = *param; + subparam.probability=0; + subparam.C=1.0; + subparam.nr_weight=2; + subparam.weight_label = Malloc(int,2); + subparam.weight = Malloc(double,2); + subparam.weight_label[0]=+1; + subparam.weight_label[1]=-1; + subparam.weight[0]=Cp; + subparam.weight[1]=Cn; + struct svm_model *submodel = svm_train(&subprob,&subparam); + for(j=begin;j<end;j++) + { + svm_predict_values(submodel,prob->x[perm[j]],&(dec_values[perm[j]])); + // ensure +1 -1 order; reason not using CV subroutine + dec_values[perm[j]] *= submodel->label[0]; + } + svm_free_and_destroy_model(&submodel); + svm_destroy_param(&subparam); + } + free(subprob.x); + free(subprob.y); + } + sigmoid_train(prob->l,dec_values,prob->y,probA,probB); + free(dec_values); + free(perm); + } + + // Return parameter of a Laplace distribution + static double svm_svr_probability( + const svm_problem *prob, const svm_parameter *param) + { + int i; + int nr_fold = 5; + double *ymv = Malloc(double,prob->l); + double mae = 0; + + svm_parameter newparam = *param; + newparam.probability = 0; + svm_cross_validation(prob,&newparam,nr_fold,ymv); + for(i=0;i<prob->l;i++) + { + ymv[i]=prob->y[i]-ymv[i]; + mae += fabs(ymv[i]); + } + mae /= prob->l; + double std=sqrt(2*mae*mae); + int count=0; + mae=0; + for(i=0;i<prob->l;i++) + if (fabs(ymv[i]) > 5*std) + count=count+1; + else + mae+=fabs(ymv[i]); + mae /= (prob->l-count); + info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma= %g\n",mae); + free(ymv); + return mae; + } + + + // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data + // perm, length l, must be allocated before calling this subroutine + static void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int **label_ret, int **start_ret, int **count_ret, int *perm) + { + int l = prob->l; + int max_nr_class = 16; + int nr_class = 0; + int *label = Malloc(int,max_nr_class); + int *count = Malloc(int,max_nr_class); + int *data_label = Malloc(int,l); + int i; + + for(i=0;i<l;i++) + { + int this_label = (int)prob->y[i]; + int j; + for(j=0;j<nr_class;j++) + { + if(this_label == label[j]) + { + ++count[j]; + break; + } + } + data_label[i] = j; + if(j == nr_class) + { + if(nr_class == max_nr_class) + { + max_nr_class *= 2; + label = (int *)realloc(label,max_nr_class*sizeof(int)); + count = (int *)realloc(count,max_nr_class*sizeof(int)); + } + label[nr_class] = this_label; + count[nr_class] = 1; + ++nr_class; + } + } + + // + // Labels are ordered by their first occurrence in the training set. + // However, for two-class sets with -1/+1 labels and -1 appears first, + // we swap labels to ensure that internally the binary SVM has positive data corresponding to the +1 instances. + // + if (nr_class == 2 && label[0] == -1 && label[1] == 1) + { + swap(label[0],label[1]); + swap(count[0],count[1]); + for(i=0;i<l;i++) + { + if(data_label[i] == 0) + data_label[i] = 1; + else + data_label[i] = 0; + } + } + + int *start = Malloc(int,nr_class); + start[0] = 0; + for(i=1;i<nr_class;i++) + start[i] = start[i-1]+count[i-1]; + for(i=0;i<l;i++) + { + perm[start[data_label[i]]] = i; + ++start[data_label[i]]; + } + start[0] = 0; + for(i=1;i<nr_class;i++) + start[i] = start[i-1]+count[i-1]; + + *nr_class_ret = nr_class; + *label_ret = label; + *start_ret = start; + *count_ret = count; + free(data_label); + } + + // + // Interface functions + // + svm_model *svm_train(const svm_problem *prob, const svm_parameter *param) + { + svm_model *model = Malloc(svm_model,1); + model->param = *param; + model->free_sv = 0; // XXX + + if(param->svm_type == ONE_CLASS || + param->svm_type == EPSILON_SVR || + param->svm_type == NU_SVR) + { + // regression or one-class-svm + model->nr_class = 2; + model->label = NULL; + model->nSV = NULL; + model->probA = NULL; model->probB = NULL; + model->sv_coef = Malloc(double *,1); + + if(param->probability && + (param->svm_type == EPSILON_SVR || + param->svm_type == NU_SVR)) + { + model->probA = Malloc(double,1); + model->probA[0] = svm_svr_probability(prob,param); + } + + decision_function f = svm_train_one(prob,param,0,0); + model->rho = Malloc(double,1); + model->rho[0] = f.rho; + + int nSV = 0; + int i; + for(i=0;i<prob->l;i++) + if(fabs(f.alpha[i]) > 0) ++nSV; + model->l = nSV; + model->SV = Malloc(svm_node *,nSV); + model->sv_coef[0] = Malloc(double,nSV); + model->sv_indices = Malloc(int,nSV); + int j = 0; + for(i=0;i<prob->l;i++) + if(fabs(f.alpha[i]) > 0) + { + model->SV[j] = prob->x[i]; + model->sv_coef[0][j] = f.alpha[i]; + model->sv_indices[j] = i+1; + ++j; + } + + free(f.alpha); + } + else + { + // classification + int l = prob->l; + int nr_class; + int *label = NULL; + int *start = NULL; + int *count = NULL; + int *perm = Malloc(int,l); + + // group training data of the same class + svm_group_classes(prob,&nr_class,&label,&start,&count,perm); + if(nr_class == 1) + info("WARNING: training data in only one class. See README for details.\n"); + + svm_node **x = Malloc(svm_node *,l); + int i; + for(i=0;i<l;i++) + x[i] = prob->x[perm[i]]; + + // calculate weighted C + + double *weighted_C = Malloc(double, nr_class); + for(i=0;i<nr_class;i++) + weighted_C[i] = param->C; + for(i=0;i<param->nr_weight;i++) + { + int j; + for(j=0;j<nr_class;j++) + if(param->weight_label[i] == label[j]) + break; + if(j == nr_class) + fprintf(stderr,"WARNING: class label %d specified in weight is not found\n", param->weight_label[i]); + else + weighted_C[j] *= param->weight[i]; + } + + // train k*(k-1)/2 models + + bool *nonzero = Malloc(bool,l); + for(i=0;i<l;i++) + nonzero[i] = false; + decision_function *f = Malloc(decision_function,nr_class*(nr_class-1)/2); + + double *probA=NULL,*probB=NULL; + if (param->probability) + { + probA=Malloc(double,nr_class*(nr_class-1)/2); + probB=Malloc(double,nr_class*(nr_class-1)/2); + } + + int p = 0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + svm_problem sub_prob; + int si = start[i], sj = start[j]; + int ci = count[i], cj = count[j]; + sub_prob.l = ci+cj; + sub_prob.x = Malloc(svm_node *,sub_prob.l); + sub_prob.y = Malloc(double,sub_prob.l); + int k; + for(k=0;k<ci;k++) + { + sub_prob.x[k] = x[si+k]; + sub_prob.y[k] = +1; + } + for(k=0;k<cj;k++) + { + sub_prob.x[ci+k] = x[sj+k]; + sub_prob.y[ci+k] = -1; + } + + if(param->probability) + svm_binary_svc_probability(&sub_prob,param,weighted_C[i],weighted_C[j],probA[p],probB[p]); + + f[p] = svm_train_one(&sub_prob,param,weighted_C[i],weighted_C[j]); + for(k=0;k<ci;k++) + if(!nonzero[si+k] && fabs(f[p].alpha[k]) > 0) + nonzero[si+k] = true; + for(k=0;k<cj;k++) + if(!nonzero[sj+k] && fabs(f[p].alpha[ci+k]) > 0) + nonzero[sj+k] = true; + free(sub_prob.x); + free(sub_prob.y); + ++p; + } + + // build output + + model->nr_class = nr_class; + + model->label = Malloc(int,nr_class); + for(i=0;i<nr_class;i++) + model->label[i] = label[i]; + + model->rho = Malloc(double,nr_class*(nr_class-1)/2); + for(i=0;i<nr_class*(nr_class-1)/2;i++) + model->rho[i] = f[i].rho; + + if(param->probability) + { + model->probA = Malloc(double,nr_class*(nr_class-1)/2); + model->probB = Malloc(double,nr_class*(nr_class-1)/2); + for(i=0;i<nr_class*(nr_class-1)/2;i++) + { + model->probA[i] = probA[i]; + model->probB[i] = probB[i]; + } + } + else + { + model->probA=NULL; + model->probB=NULL; + } + + int total_sv = 0; + int *nz_count = Malloc(int,nr_class); + model->nSV = Malloc(int,nr_class); + for(i=0;i<nr_class;i++) + { + int nSV = 0; + for(int j=0;j<count[i];j++) + if(nonzero[start[i]+j]) + { + ++nSV; + ++total_sv; + } + model->nSV[i] = nSV; + nz_count[i] = nSV; + } + + info("Total nSV = %d\n",total_sv); + + model->l = total_sv; + model->SV = Malloc(svm_node *,total_sv); + model->sv_indices = Malloc(int,total_sv); + p = 0; + for(i=0;i<l;i++) + if(nonzero[i]) + { + model->SV[p] = x[i]; + model->sv_indices[p++] = perm[i] + 1; + } + + int *nz_start = Malloc(int,nr_class); + nz_start[0] = 0; + for(i=1;i<nr_class;i++) + nz_start[i] = nz_start[i-1]+nz_count[i-1]; + + model->sv_coef = Malloc(double *,nr_class-1); + for(i=0;i<nr_class-1;i++) + model->sv_coef[i] = Malloc(double,total_sv); + + p = 0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + // classifier (i,j): coefficients with + // i are in sv_coef[j-1][nz_start[i]...], + // j are in sv_coef[i][nz_start[j]...] + + int si = start[i]; + int sj = start[j]; + int ci = count[i]; + int cj = count[j]; + + int q = nz_start[i]; + int k; + for(k=0;k<ci;k++) + if(nonzero[si+k]) + model->sv_coef[j-1][q++] = f[p].alpha[k]; + q = nz_start[j]; + for(k=0;k<cj;k++) + if(nonzero[sj+k]) + model->sv_coef[i][q++] = f[p].alpha[ci+k]; + ++p; + } + + free(label); + free(probA); + free(probB); + free(count); + free(perm); + free(start); + free(x); + free(weighted_C); + free(nonzero); + for(i=0;i<nr_class*(nr_class-1)/2;i++) + free(f[i].alpha); + free(f); + free(nz_count); + free(nz_start); + } + return model; + } + + // Stratified cross validation + void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, int nr_fold, double *target) + { + int i; + int *fold_start; + int l = prob->l; + int *perm = Malloc(int,l); + int nr_class; + if (nr_fold > l) + { + nr_fold = l; + fprintf(stderr,"WARNING: # folds > # data. Will use # folds = # data instead (i.e., leave-one-out cross validation)\n"); + } + fold_start = Malloc(int,nr_fold+1); + // stratified cv may not give leave-one-out rate + // Each class to l folds -> some folds may have zero elements + if((param->svm_type == C_SVC || + param->svm_type == NU_SVC) && nr_fold < l) + { + int *start = NULL; + int *label = NULL; + int *count = NULL; + svm_group_classes(prob,&nr_class,&label,&start,&count,perm); + + // random shuffle and then data grouped by fold using the array perm + int *fold_count = Malloc(int,nr_fold); + int c; + int *index = Malloc(int,l); + for(i=0;i<l;i++) + index[i]=perm[i]; + for (c=0; c<nr_class; c++) + for(i=0;i<count[c];i++) + { + int j = i+rand()%(count[c]-i); + swap(index[start[c]+j],index[start[c]+i]); + } + for(i=0;i<nr_fold;i++) + { + fold_count[i] = 0; + for (c=0; c<nr_class;c++) + fold_count[i]+=(i+1)*count[c]/nr_fold-i*count[c]/nr_fold; + } + fold_start[0]=0; + for (i=1;i<=nr_fold;i++) + fold_start[i] = fold_start[i-1]+fold_count[i-1]; + for (c=0; c<nr_class;c++) + for(i=0;i<nr_fold;i++) + { + int begin = start[c]+i*count[c]/nr_fold; + int end = start[c]+(i+1)*count[c]/nr_fold; + for(int j=begin;j<end;j++) + { + perm[fold_start[i]] = index[j]; + fold_start[i]++; + } + } + fold_start[0]=0; + for (i=1;i<=nr_fold;i++) + fold_start[i] = fold_start[i-1]+fold_count[i-1]; + free(start); + free(label); + free(count); + free(index); + free(fold_count); + } + else + { + for(i=0;i<l;i++) perm[i]=i; + for(i=0;i<l;i++) + { + int j = i+rand()%(l-i); + swap(perm[i],perm[j]); + } + for(i=0;i<=nr_fold;i++) + fold_start[i]=i*l/nr_fold; + } + + for(i=0;i<nr_fold;i++) + { + int begin = fold_start[i]; + int end = fold_start[i+1]; + int j,k; + struct svm_problem subprob; + + subprob.l = l-(end-begin); + subprob.x = Malloc(struct svm_node*,subprob.l); + subprob.y = Malloc(double,subprob.l); + + k=0; + for(j=0;j<begin;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + for(j=end;j<l;j++) + { + subprob.x[k] = prob->x[perm[j]]; + subprob.y[k] = prob->y[perm[j]]; + ++k; + } + struct svm_model *submodel = svm_train(&subprob,param); + if(param->probability && + (param->svm_type == C_SVC || param->svm_type == NU_SVC)) + { + double *prob_estimates=Malloc(double,svm_get_nr_class(submodel)); + for(j=begin;j<end;j++) + target[perm[j]] = svm_predict_probability(submodel,prob->x[perm[j]],prob_estimates); + free(prob_estimates); + } + else + for(j=begin;j<end;j++) + target[perm[j]] = svm_predict(submodel,prob->x[perm[j]]); + svm_free_and_destroy_model(&submodel); + free(subprob.x); + free(subprob.y); + } + free(fold_start); + free(perm); + } + + + int svm_get_svm_type(const svm_model *model) + { + return model->param.svm_type; + } + + int svm_get_nr_class(const svm_model *model) + { + return model->nr_class; + } + + void svm_get_labels(const svm_model *model, int* label) + { + if (model->label != NULL) + for(int i=0;i<model->nr_class;i++) + label[i] = model->label[i]; + } + + void svm_get_sv_indices(const svm_model *model, int* indices) + { + if (model->sv_indices != NULL) + for(int i=0;i<model->l;i++) + indices[i] = model->sv_indices[i]; + } + + int svm_get_nr_sv(const svm_model *model) + { + return model->l; + } + + double svm_get_svr_probability(const svm_model *model) + { + if ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) && + model->probA!=NULL) + return model->probA[0]; + else + { + fprintf(stderr,"Model doesn't contain information for SVR probability inference\n"); + return 0; + } + } + + double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values) + { + int i; + if(model->param.svm_type == ONE_CLASS || + model->param.svm_type == EPSILON_SVR || + model->param.svm_type == NU_SVR) + { + double *sv_coef = model->sv_coef[0]; + double sum = 0; + for(i=0;i<model->l;i++) + sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param); + sum -= model->rho[0]; + *dec_values = sum; + + if(model->param.svm_type == ONE_CLASS) + return (sum>0)?1:-1; + else + return sum; + } + else + { + int nr_class = model->nr_class; + int l = model->l; + + double *kvalue = Malloc(double,l); + for(i=0;i<l;i++) + kvalue[i] = Kernel::k_function(x,model->SV[i],model->param); + + int *start = Malloc(int,nr_class); + start[0] = 0; + for(i=1;i<nr_class;i++) + start[i] = start[i-1]+model->nSV[i-1]; + + int *vote = Malloc(int,nr_class); + for(i=0;i<nr_class;i++) + vote[i] = 0; + + int p=0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + double sum = 0; + int si = start[i]; + int sj = start[j]; + int ci = model->nSV[i]; + int cj = model->nSV[j]; + + int k; + double *coef1 = model->sv_coef[j-1]; + double *coef2 = model->sv_coef[i]; + for(k=0;k<ci;k++) + sum += coef1[si+k] * kvalue[si+k]; + for(k=0;k<cj;k++) + sum += coef2[sj+k] * kvalue[sj+k]; + sum -= model->rho[p]; + dec_values[p] = sum; + + if(dec_values[p] > 0) + ++vote[i]; + else + ++vote[j]; + p++; + } + + int vote_max_idx = 0; + for(i=1;i<nr_class;i++) + if(vote[i] > vote[vote_max_idx]) + vote_max_idx = i; + + free(kvalue); + free(start); + free(vote); + return model->label[vote_max_idx]; + } + } + + double svm_predict(const svm_model *model, const svm_node *x) + { + int nr_class = model->nr_class; + double *dec_values; + if(model->param.svm_type == ONE_CLASS || + model->param.svm_type == EPSILON_SVR || + model->param.svm_type == NU_SVR) + dec_values = Malloc(double, 1); + else + dec_values = Malloc(double, nr_class*(nr_class-1)/2); + double pred_result = svm_predict_values(model, x, dec_values); + free(dec_values); + return pred_result; + } + + double svm_predict_probability( + const svm_model *model, const svm_node *x, double *prob_estimates) + { + if ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) && + model->probA!=NULL && model->probB!=NULL) + { + int i; + int nr_class = model->nr_class; + double *dec_values = Malloc(double, nr_class*(nr_class-1)/2); + svm_predict_values(model, x, dec_values); + + double min_prob=1e-7; + double **pairwise_prob=Malloc(double *,nr_class); + for(i=0;i<nr_class;i++) + pairwise_prob[i]=Malloc(double,nr_class); + int k=0; + for(i=0;i<nr_class;i++) + for(int j=i+1;j<nr_class;j++) + { + pairwise_prob[i][j]=min(max(sigmoid_predict(dec_values[k],model->probA[k],model->probB[k]),min_prob),1-min_prob); + pairwise_prob[j][i]=1-pairwise_prob[i][j]; + k++; + } + if (nr_class == 2) + { + prob_estimates[0] = pairwise_prob[0][1]; + prob_estimates[1] = pairwise_prob[1][0]; + } + else + multiclass_probability(nr_class,pairwise_prob,prob_estimates); + + int prob_max_idx = 0; + for(i=1;i<nr_class;i++) + if(prob_estimates[i] > prob_estimates[prob_max_idx]) + prob_max_idx = i; + for(i=0;i<nr_class;i++) + free(pairwise_prob[i]); + free(dec_values); + free(pairwise_prob); + return model->label[prob_max_idx]; + } + else + return svm_predict(model, x); + } + + static const char *svm_type_table[] = + { + "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",NULL + }; + + static const char *kernel_type_table[]= + { + "linear","polynomial","rbf","sigmoid","precomputed",NULL + }; + + int svm_save_model(const char *model_file_name, const svm_model *model) + { + FILE *fp = fopen(model_file_name,"w"); + if(fp==NULL) return -1; + + char *old_locale = setlocale(LC_ALL, NULL); + if (old_locale) { + old_locale = strdup(old_locale); + } + setlocale(LC_ALL, "C"); + + const svm_parameter& param = model->param; + + fprintf(fp,"svm_type %s\n", svm_type_table[param.svm_type]); + fprintf(fp,"kernel_type %s\n", kernel_type_table[param.kernel_type]); + + if(param.kernel_type == POLY) + fprintf(fp,"degree %d\n", param.degree); + + if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID) + fprintf(fp,"gamma %g\n", param.gamma); + + if(param.kernel_type == POLY || param.kernel_type == SIGMOID) + fprintf(fp,"coef0 %g\n", param.coef0); + + int nr_class = model->nr_class; + int l = model->l; + fprintf(fp, "nr_class %d\n", nr_class); + fprintf(fp, "total_sv %d\n",l); + + { + fprintf(fp, "rho"); + for(int i=0;i<nr_class*(nr_class-1)/2;i++) + fprintf(fp," %g",model->rho[i]); + fprintf(fp, "\n"); + } + + if(model->label) + { + fprintf(fp, "label"); + for(int i=0;i<nr_class;i++) + fprintf(fp," %d",model->label[i]); + fprintf(fp, "\n"); + } + + if(model->probA) // regression has probA only + { + fprintf(fp, "probA"); + for(int i=0;i<nr_class*(nr_class-1)/2;i++) + fprintf(fp," %g",model->probA[i]); + fprintf(fp, "\n"); + } + if(model->probB) + { + fprintf(fp, "probB"); + for(int i=0;i<nr_class*(nr_class-1)/2;i++) + fprintf(fp," %g",model->probB[i]); + fprintf(fp, "\n"); + } + + if(model->nSV) + { + fprintf(fp, "nr_sv"); + for(int i=0;i<nr_class;i++) + fprintf(fp," %d",model->nSV[i]); + fprintf(fp, "\n"); + } + + fprintf(fp, "SV\n"); + const double * const *sv_coef = model->sv_coef; + const svm_node * const *SV = model->SV; + + for(int i=0;i<l;i++) + { + for(int j=0;j<nr_class-1;j++) + fprintf(fp, "%.16g ",sv_coef[j][i]); + + const svm_node *p = SV[i]; + + if(param.kernel_type == PRECOMPUTED) + fprintf(fp,"0:%d ",(int)(p->value)); + else + while(p->index != -1) + { + fprintf(fp,"%d:%.8g ",p->index,p->value); + p++; + } + fprintf(fp, "\n"); + } + + setlocale(LC_ALL, old_locale); + free(old_locale); + + if (ferror(fp) != 0 || fclose(fp) != 0) return -1; + else return 0; + } + + static char *line = NULL; + static int max_line_len; + + static char* readline(FILE *input) + { + int len; + + if(fgets(line,max_line_len,input) == NULL) + return NULL; + + while(strrchr(line,'\n') == NULL) + { + max_line_len *= 2; + line = (char *) realloc(line,max_line_len); + len = (int) strlen(line); + if(fgets(line+len,max_line_len-len,input) == NULL) + break; + } + return line; + } + + // + // FSCANF helps to handle fscanf failures. + // Its do-while block avoids the ambiguity when + // if (...) + // FSCANF(); + // is used + // +#define FSCANF(_stream, _format, _var) do{ if (fscanf(_stream, _format, _var) != 1) return false; }while(0) + bool read_model_header(FILE *fp, svm_model* model) + { + svm_parameter& param = model->param; + // parameters for training only won't be assigned, but arrays are assigned as NULL for safety + param.nr_weight = 0; + param.weight_label = NULL; + param.weight = NULL; + + char cmd[81]; + while(1) + { + FSCANF(fp,"%80s",cmd); + + if(strcmp(cmd,"svm_type")==0) + { + FSCANF(fp,"%80s",cmd); + int i; + for(i=0;svm_type_table[i];i++) + { + if(strcmp(svm_type_table[i],cmd)==0) + { + param.svm_type=i; + break; + } + } + if(svm_type_table[i] == NULL) + { + fprintf(stderr,"unknown svm type.\n"); + return false; + } + } + else if(strcmp(cmd,"kernel_type")==0) + { + FSCANF(fp,"%80s",cmd); + int i; + for(i=0;kernel_type_table[i];i++) + { + if(strcmp(kernel_type_table[i],cmd)==0) + { + param.kernel_type=i; + break; + } + } + if(kernel_type_table[i] == NULL) + { + fprintf(stderr,"unknown kernel function.\n"); + return false; + } + } + else if(strcmp(cmd,"degree")==0) + FSCANF(fp,"%d",¶m.degree); + else if(strcmp(cmd,"gamma")==0) + FSCANF(fp,"%lf",¶m.gamma); + else if(strcmp(cmd,"coef0")==0) + FSCANF(fp,"%lf",¶m.coef0); + else if(strcmp(cmd,"nr_class")==0) + FSCANF(fp,"%d",&model->nr_class); + else if(strcmp(cmd,"total_sv")==0) + FSCANF(fp,"%d",&model->l); + else if(strcmp(cmd,"rho")==0) + { + int n = model->nr_class * (model->nr_class-1)/2; + model->rho = Malloc(double,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%lf",&model->rho[i]); + } + else if(strcmp(cmd,"label")==0) + { + int n = model->nr_class; + model->label = Malloc(int,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%d",&model->label[i]); + } + else if(strcmp(cmd,"probA")==0) + { + int n = model->nr_class * (model->nr_class-1)/2; + model->probA = Malloc(double,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%lf",&model->probA[i]); + } + else if(strcmp(cmd,"probB")==0) + { + int n = model->nr_class * (model->nr_class-1)/2; + model->probB = Malloc(double,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%lf",&model->probB[i]); + } + else if(strcmp(cmd,"nr_sv")==0) + { + int n = model->nr_class; + model->nSV = Malloc(int,n); + for(int i=0;i<n;i++) + FSCANF(fp,"%d",&model->nSV[i]); + } + else if(strcmp(cmd,"SV")==0) + { + while(1) + { + int c = getc(fp); + if(c==EOF || c=='\n') break; + } + break; + } + else + { + fprintf(stderr,"unknown text in model file: [%s]\n",cmd); + return false; + } + } + + return true; + + } + + svm_model *svm_load_model(const char *model_file_name) + { + FILE *fp = fopen(model_file_name,"rb"); + if(fp==NULL) return NULL; + + char *old_locale = setlocale(LC_ALL, NULL); + if (old_locale) { + old_locale = strdup(old_locale); + } + setlocale(LC_ALL, "C"); + + // read parameters + + svm_model *model = Malloc(svm_model,1); + model->rho = NULL; + model->probA = NULL; + model->probB = NULL; + model->sv_indices = NULL; + model->label = NULL; + model->nSV = NULL; + + // read header + if (!read_model_header(fp, model)) + { + fprintf(stderr, "ERROR: fscanf failed to read model\n"); + setlocale(LC_ALL, old_locale); + free(old_locale); + free(model->rho); + free(model->label); + free(model->nSV); + free(model); + return NULL; + } + + // read sv_coef and SV + + int elements = 0; + long pos = ftell(fp); + + max_line_len = 1024; + line = Malloc(char,max_line_len); + char *p,*endptr,*idx,*val; + + while(readline(fp)!=NULL) + { + p = strtok(line,":"); + while(1) + { + p = strtok(NULL,":"); + if(p == NULL) + break; + ++elements; + } + } + elements += model->l; + + fseek(fp,pos,SEEK_SET); + + int m = model->nr_class - 1; + int l = model->l; + model->sv_coef = Malloc(double *,m); + int i; + for(i=0;i<m;i++) + model->sv_coef[i] = Malloc(double,l); + model->SV = Malloc(svm_node*,l); + svm_node *x_space = NULL; + if(l>0) x_space = Malloc(svm_node,elements); + + int j=0; + for(i=0;i<l;i++) + { + readline(fp); + model->SV[i] = &x_space[j]; + + p = strtok(line, " \t"); + model->sv_coef[0][i] = strtod(p,&endptr); + for(int k=1;k<m;k++) + { + p = strtok(NULL, " \t"); + model->sv_coef[k][i] = strtod(p,&endptr); + } + + while(1) + { + idx = strtok(NULL, ":"); + val = strtok(NULL, " \t"); + + if(val == NULL) + break; + x_space[j].index = (int) strtol(idx,&endptr,10); + x_space[j].value = strtod(val,&endptr); + + ++j; + } + x_space[j++].index = -1; + } + free(line); + + setlocale(LC_ALL, old_locale); + free(old_locale); + + if (ferror(fp) != 0 || fclose(fp) != 0) + return NULL; + + model->free_sv = 1; // XXX + return model; + } + + void svm_free_model_content(svm_model* model_ptr) + { + if(model_ptr->free_sv && model_ptr->l > 0 && model_ptr->SV != NULL) + free((void *)(model_ptr->SV[0])); + if(model_ptr->sv_coef) + { + for(int i=0;i<model_ptr->nr_class-1;i++) + free(model_ptr->sv_coef[i]); + } + + free(model_ptr->SV); + model_ptr->SV = NULL; + + free(model_ptr->sv_coef); + model_ptr->sv_coef = NULL; + + free(model_ptr->rho); + model_ptr->rho = NULL; + + free(model_ptr->label); + model_ptr->label= NULL; + + free(model_ptr->probA); + model_ptr->probA = NULL; + + free(model_ptr->probB); + model_ptr->probB= NULL; + + free(model_ptr->sv_indices); + model_ptr->sv_indices = NULL; + + free(model_ptr->nSV); + model_ptr->nSV = NULL; + } + + void svm_free_and_destroy_model(svm_model** model_ptr_ptr) + { + if(model_ptr_ptr != NULL && *model_ptr_ptr != NULL) + { + svm_free_model_content(*model_ptr_ptr); + free(*model_ptr_ptr); + *model_ptr_ptr = NULL; + } + } + + void svm_destroy_param(svm_parameter* param) + { + free(param->weight_label); + free(param->weight); + } + + const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *param) + { + // svm_type + + int svm_type = param->svm_type; + if(svm_type != C_SVC && + svm_type != NU_SVC && + svm_type != ONE_CLASS && + svm_type != EPSILON_SVR && + svm_type != NU_SVR) + return "unknown svm type"; + + // kernel_type, degree + + int kernel_type = param->kernel_type; + if(kernel_type != LINEAR && + kernel_type != POLY && + kernel_type != RBF && + kernel_type != SIGMOID && + kernel_type != PRECOMPUTED) + return "unknown kernel type"; + + if(param->gamma < 0) + return "gamma < 0"; + + if(param->degree < 0) + return "degree of polynomial kernel < 0"; + + // cache_size,eps,C,nu,p,shrinking + + if(param->cache_size <= 0) + return "cache_size <= 0"; + + if(param->eps <= 0) + return "eps <= 0"; + + if(svm_type == C_SVC || + svm_type == EPSILON_SVR || + svm_type == NU_SVR) + if(param->C <= 0) + return "C <= 0"; + + if(svm_type == NU_SVC || + svm_type == ONE_CLASS || + svm_type == NU_SVR) + if(param->nu <= 0 || param->nu > 1) + return "nu <= 0 or nu > 1"; + + if(svm_type == EPSILON_SVR) + if(param->p < 0) + return "p < 0"; + + if(param->shrinking != 0 && + param->shrinking != 1) + return "shrinking != 0 and shrinking != 1"; + + if(param->probability != 0 && + param->probability != 1) + return "probability != 0 and probability != 1"; + + if(param->probability == 1 && + svm_type == ONE_CLASS) + return "one-class SVM probability output not supported yet"; + + + // check whether nu-svc is feasible + + if(svm_type == NU_SVC) + { + int l = prob->l; + int max_nr_class = 16; + int nr_class = 0; + int *label = Malloc(int,max_nr_class); + int *count = Malloc(int,max_nr_class); + + int i; + for(i=0;i<l;i++) + { + int this_label = (int)prob->y[i]; + int j; + for(j=0;j<nr_class;j++) + if(this_label == label[j]) + { + ++count[j]; + break; + } + if(j == nr_class) + { + if(nr_class == max_nr_class) + { + max_nr_class *= 2; + label = (int *)realloc(label,max_nr_class*sizeof(int)); + count = (int *)realloc(count,max_nr_class*sizeof(int)); + } + label[nr_class] = this_label; + count[nr_class] = 1; + ++nr_class; + } + } + + for(i=0;i<nr_class;i++) + { + int n1 = count[i]; + for(int j=i+1;j<nr_class;j++) + { + int n2 = count[j]; + if(param->nu*(n1+n2)/2 > min(n1,n2)) + { + free(label); + free(count); + return "specified nu is infeasible"; + } + } + } + free(label); + free(count); + } + + return NULL; + } + + int svm_check_probability_model(const svm_model *model) + { + return ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) && + model->probA!=NULL && model->probB!=NULL) || + ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) && + model->probA!=NULL); + } + + void svm_set_print_string_function(void (*print_func)(const char *)) + { + if(print_func == NULL) + svm_print_string = &print_string_stdout; + else + svm_print_string = print_func; + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/libsvm.h b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/libsvm.h new file mode 100644 index 0000000000000000000000000000000000000000..b1f583202b3d49fd30957ad7d4e6aea9804aad9e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/third_party/libsvm/libsvm.h @@ -0,0 +1,108 @@ +#ifndef _LIBSVM_H +#define _LIBSVM_H + +namespace LIBSVM { + +#define LIBSVM_VERSION 322 + +#ifdef __cplusplus + extern "C" { +#endif + + extern int libsvm_version; + + struct svm_node + { + int index; + double value; + }; + + struct svm_problem + { + int l; + double *y; + struct svm_node **x; + }; + + enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR }; /* svm_type */ + enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED }; /* kernel_type */ + + struct svm_parameter + { + int svm_type; + int kernel_type; + int degree; /* for poly */ + double gamma; /* for poly/rbf/sigmoid */ + double coef0; /* for poly/sigmoid */ + + /* these are for training only */ + double cache_size; /* in MB */ + double eps; /* stopping criteria */ + double C; /* for C_SVC, EPSILON_SVR and NU_SVR */ + int nr_weight; /* for C_SVC */ + int *weight_label; /* for C_SVC */ + double* weight; /* for C_SVC */ + double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */ + double p; /* for EPSILON_SVR */ + int shrinking; /* use the shrinking heuristics */ + int probability; /* do probability estimates */ + }; + + // + // svm_model + // + struct svm_model + { + struct svm_parameter param; /* parameter */ + int nr_class; /* number of classes, = 2 in regression/one class svm */ + int l; /* total #SV */ + struct svm_node **SV; /* SVs (SV[l]) */ + double **sv_coef; /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */ + double *rho; /* constants in decision functions (rho[k*(k-1)/2]) */ + double *probA; /* pariwise probability information */ + double *probB; + int *sv_indices; /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */ + + /* for classification only */ + + int *label; /* label of each class (label[k]) */ + int *nSV; /* number of SVs for each class (nSV[k]) */ + /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ + /* XXX */ + int free_sv; /* 1 if svm_model is created by svm_load_model*/ + /* 0 if svm_model is created by svm_train */ + }; + + struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param); + void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter *param, int nr_fold, double *target); + + int svm_save_model(const char *model_file_name, const struct svm_model *model); + struct svm_model *svm_load_model(const char *model_file_name); + + int svm_get_svm_type(const struct svm_model *model); + int svm_get_nr_class(const struct svm_model *model); + void svm_get_labels(const struct svm_model *model, int *label); + void svm_get_sv_indices(const struct svm_model *model, int *sv_indices); + int svm_get_nr_sv(const struct svm_model *model); + double svm_get_svr_probability(const struct svm_model *model); + + double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values); + double svm_predict(const struct svm_model *model, const struct svm_node *x); + double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates); + + void svm_free_model_content(struct svm_model *model_ptr); + void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr); + void svm_destroy_param(struct svm_parameter *param); + + const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param); + int svm_check_probability_model(const struct svm_model *model); + + void svm_set_print_string_function(void (*print_func)(const char *)); + +#ifdef __cplusplus + } +#endif + +} + +#endif /* _LIBSVM_H */ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/.gitignore b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5263c7451ce24e7954b55d3777e62fe09731df25 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/.gitignore @@ -0,0 +1,27 @@ +ide/xcode/build +ide/xcode/xmm-lib.xcodeproj/project.xcworkspace +ide/xcode/xmm-lib.xcodeproj/xcuserdata +dependencies/libjson/ide/build +dependencies/libjson/ide/json.xcodeproj/xcuserdata +dependencies/libjson/ide/json.xcodeproj/project.xcworkspace/xcuserdata +dependencies/libjson/Makefile +doc/html +doc/xml +bin +Makefile +python/Makefile +CMakeFiles +python/bin +python/xmm.py +python/xmm_doc.i +python/xmmPYTHON_wrap.cxx +python/bin +python/_build_tmp +*CMakeCache.txt +*cmake_install.cmake +*pyc +*.a +*.so +*.dylib +*.ipynb_checkpoints +cmake_clean.sh diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/CMakeLists.txt b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d27bf0425b3502689e7fc397e03b80b95714aae --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/CMakeLists.txt @@ -0,0 +1,111 @@ +cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) + +# Project declaration +project(xmm) + +include(CheckCXXCompilerFlag) +CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) +CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +elseif(COMPILER_SUPPORTS_CXX0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +else() + message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") +endif() + +# The version number. +set (xmm_VERSION_MAJOR 0) +set (xmm_VERSION_MINOR 1) + +# Compiler Flags +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -fPIC") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -DJSON_DEBUG -fPIC") +if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release") +endif() + +# Include JSON +include_directories(./dependencies/jsoncpp/include) +include_directories(./dependencies/jsoncpp/src) + +# Declare library +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/core/common) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/core/distributions) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/core/model) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/core/trainingset) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/models/gmm) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/models/hmm) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/models/kmeans) + +set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}) +add_definitions(-DUSE_PTHREAD) + +file( + GLOB_RECURSE + xmm_source_files + src/* +) + +file( + GLOB_RECURSE + jsoncpp_source_files + dependencies/jsoncpp/src/* +) + +add_library( + xmm + STATIC + ${xmm_source_files} ${jsoncpp_source_files} +) + +# Declare Unit tests +set(EXECUTABLE_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/catch) + +# message(${LINK_DIRECTORIES}) + +file( + GLOB_RECURSE + xmm_test_files + test/* +) + +add_executable( + tests + EXCLUDE_FROM_ALL + ${xmm_test_files} +) + +# linking configuration +target_link_libraries( + tests + xmm +) + +set_target_properties(tests PROPERTIES OUTPUT_NAME xmm_testing) +add_custom_command(TARGET tests POST_BUILD COMMAND ${EXECUTABLE_OUTPUT_PATH}/xmm_testing) + +# add a target to generate API documentation with Doxygen +find_package(Doxygen) + +find_program(DOTPATH dot) +if(${DOTPATH} STREQUAL "DOTPATH-NOTFOUND") + set(HAS_DOT "") +else(${DOTPATH} STREQUAL "DOTPATH-NOTFOUND") + set(HAS_DOT "-dot") +endif(${DOTPATH} STREQUAL "DOTPATH-NOTFOUND") + +if(DOXYGEN_FOUND) + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile${HAS_DOT} + DEPENDS ${tracking_source_files} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc/ + COMMENT "Generating API documentation with Doxygen" VERBATIM) +else(DOXYGEN_FOUND) + message(STATUS "Doxygen not found, doc will not be included in the Makefile") +endif(DOXYGEN_FOUND) + +set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/doc/html") diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/LICENSE b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..6b156fe1db9c5cd21ca1c68b7025bae40d0c5764 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/LICENSE @@ -0,0 +1,675 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/catch/catch.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/catch/catch.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5b616a2b60d8dfcf6eb7f9bb18e6680554249fb8 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/catch/catch.hpp @@ -0,0 +1,9427 @@ +/* + * CATCH v1.1 build 1 (master branch) + * Generated: 2015-03-27 18:00:16.346230 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +// #included from: internal/catch_suppress_warnings.h + +#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif + +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include <sstream> +#include <stdexcept> +#include <algorithm> + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Much of the following code is based on Boost (1.53) + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_CONFIG_CPP11_NOEXCEPT +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#if (__BORLANDC__ > 0x582 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#if (__EDG_VERSION__ > 238 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#if (__DMC__ > 0x840 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ < 3 + +#if (__GNUC_MINOR__ >= 96 ) +//#define CATCH_CONFIG_SFINAE +#endif + +#elif __GNUC__ >= 3 + +// #define CATCH_CONFIG_SFINAE // Taking this out completely for now + +#endif // __GNUC__ < 3 + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) + +#define CATCH_CONFIG_CPP11_NULLPTR +#endif + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CATCH_CONFIG_CPP11_NULLPTR +#endif + +#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // _MSC_VER + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS +#define CATCH_CONFIG_VARIADIC_MACROS +#endif + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// detect language version: +#if (__cplusplus == 201103L) +# define CATCH_CPP11 +# define CATCH_CPP11_OR_GREATER +#elif (__cplusplus >= 201103L) +# define CATCH_CPP11_OR_GREATER +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +namespace Catch { + + class NonCopyable { +#ifdef CATCH_CPP11_OR_GREATER + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template<typename ContainerT> + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template<typename AssociativeContainerT> + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CPP11_OR_GREATER + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template<typename T> + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include <ostream> + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include <string> + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template<typename T> + class Ptr { + public: + Ptr() : m_p( NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() { return m_p; } + const T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template<typename T = IShared> + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include <memory> +#include <vector> +#include <stdlib.h> + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr<IConfig const> getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr<IConfig const> const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include <vector> + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector<TestCase> const& getAllTests() const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const = 0; + + }; +} + +namespace Catch { + +template<typename C> +class MethodTestCase : public SharedImpl<ITestCase> { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +struct AutoReg { + + AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template<typename C> + AutoReg( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + registerTestCase( new MethodTestCase<C>( method ), + className, + nameAndDesc, + lineInfo ); + } + + void registerTestCase( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x00, + + ContinueOnFailure = 0x01, // Failures fail test, but execution continues + FalseTest = 0x02, // Prefix expression with ! + SuppressFail = 0x04 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include <string> + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CPP11_OR_GREATER + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template<typename T> class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ); + + template<typename T> + ExpressionLhs<T const&> operator->* ( T const& operand ); + ExpressionLhs<bool> operator->* ( bool value ); + + template<typename T> + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include <cstddef> + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } }; + + template<typename T> + inline T& opCast(T const& t) { return const_cast<T&>(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template<typename T1, typename T2, Operator Op> + class Evaluator{}; + + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return opCast( lhs ) == opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsNotEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) != opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsLessThan> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) < opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsGreaterThan> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) > opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) >= opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsLessThanOrEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) <= opCast( rhs ); + } + }; + + template<Operator Op, typename T1, typename T2> + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template<Operator Op, typename T1, typename T2> + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); + } + + // unsigned X to int + template<Operator Op> bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + template<Operator Op> bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + template<Operator Op> bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + + // unsigned X to long + template<Operator Op> bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + template<Operator Op> bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + template<Operator Op> bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + + // int to unsigned X + template<Operator Op> bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + template<Operator Op> bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + template<Operator Op> bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + + // long to unsigned X + template<Operator Op> bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template<Operator Op, typename T> bool compare( long lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, long rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template<Operator Op, typename T> bool compare( int lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, int rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( NULL, rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, NULL ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +// #included from: catch_sfinae.hpp +#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED + +// Try to detect if the current compiler supports SFINAE + +namespace Catch { + + struct TrueType { + static const bool value = true; + typedef void Enable; + char sizer[1]; + }; + struct FalseType { + static const bool value = false; + typedef void Disable; + char sizer[2]; + }; + +#ifdef CATCH_CONFIG_SFINAE + + template<bool> struct NotABooleanExpression; + + template<bool c> struct If : NotABooleanExpression<c> {}; + template<> struct If<true> : TrueType {}; + template<> struct If<false> : FalseType {}; + + template<int size> struct SizedIf; + template<> struct SizedIf<sizeof(TrueType)> : TrueType {}; + template<> struct SizedIf<sizeof(FalseType)> : FalseType {}; + +#endif // CATCH_CONFIG_SFINAE + +} // end namespace Catch + +#include <sstream> +#include <iomanip> +#include <limits> +#include <vector> +#include <cstddef> + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import <Foundation/Foundation.h> + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CPP11_OR_GREATER +#include <tuple> +#include <type_traits> +#endif + +namespace Catch { + +// Why we're here. +template<typename T> +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern std::string unprintableString; + +// SFINAE is currently disabled by default for all compilers. +// If the non SFINAE version of IsStreamInsertable is ambiguous for you +// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE +#ifdef CATCH_CONFIG_SFINAE + + template<typename T> + class IsStreamInsertableHelper { + template<int N> struct TrueIfSizeable : TrueType {}; + + template<typename T2> + static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*); + static FalseType dummy(...); + + public: + typedef SizedIf<sizeof(dummy((T*)0))> type; + }; + + template<typename T> + struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {}; + +#else + + struct BorgType { + template<typename T> BorgType( T const& ); + }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template<typename T> + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#endif + +#if defined(CATCH_CPP11_OR_GREATER) + template<typename T, + bool IsEnum = std::is_enum<T>::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template<typename T> + struct EnumStringMaker<T,true> + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast<typename std::underlying_type<T>::type>(v) + ); + } + }; +#endif + template<bool C> + struct StringMakerBase { +#if defined(CATCH_CPP11_OR_GREATER) + template<typename T> + static std::string convert( T const& v ) + { + return EnumStringMaker<T>::convert( v ); + } +#else + template<typename T> + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase<true> { + template<typename T> + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template<typename T> + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template<typename T> +struct StringMaker : + Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; + +template<typename T> +struct StringMaker<T*> { + template<typename U> + static std::string convert( U* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +template<typename R, typename C> +struct StringMaker<R C::*> { + static std::string convert( R C::* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template<typename InputIterator> + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template<typename T, typename Allocator> +//struct StringMaker<std::vector<T, Allocator> > { +// static std::string convert( std::vector<T,Allocator> const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template<typename T, typename Allocator> +std::string toString( std::vector<T,Allocator> const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CPP11_OR_GREATER + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size<Tuple>::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get<N>(tuple)); + ElementPrinter<Tuple,N+1>::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter<Tuple,N,false> { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template<typename ...Types> +struct StringMaker<std::tuple<Types...>> { + + static std::string convert( const std::tuple<Types...>& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif + +namespace Detail { + template<typename T> + std::string makeString( T const& value ) { + return StringMaker<T>::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template<typename T> +std::string toString( T const& value ) { + return StringMaker<T>::convert( value ); +} + + namespace Detail { + template<typename InputIterator> + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template<typename T> +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CPP11_OR_GREATER + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CPP11_OR_GREATER + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template<typename RhsT> + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression<Internal::IsEqualTo>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression<Internal::IsNotEqualTo>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression<Internal::IsLessThan>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression<Internal::IsGreaterThan>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression<Internal::IsEqualTo>( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression<Internal::IsNotEqualTo>( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template<Internal::Operator Op, typename RhsT> + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare<Op>( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits<Op>::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template<typename T> + inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) { + return ExpressionLhs<T const&>( *this, operand ); + } + + inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) { + return ExpressionLhs<bool>( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include <string> + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template<typename T> + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include <string> + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include <string> + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + ( __catchResult->*expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include <cstddef> + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include <stdint.h> +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include <string> + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include <iterator> +#include <vector> +#include <string> +#include <stdlib.h> + +namespace Catch { + +template<typename T> +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template<typename T> +class BetweenGenerator : public IGenerator<T> { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast<int>( index ); + } + + virtual std::size_t size() const { + return static_cast<std::size_t>( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template<typename T> +class ValuesGenerator : public IGenerator<T> { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector<T> m_values; +}; + +template<typename T> +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); + typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator<T>* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator<T>* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector<const IGenerator<T>*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template<typename T> + CompositeGenerator<T> between( T from, T to ) { + CompositeGenerator<T> generators; + generators.add( new BetweenGenerator<T>( from, to ) ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2 ) { + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2, T val3 ){ + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include <string> +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include <string> + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate() const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template<typename T> + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate() const { + try { + throw; + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template<typename T> + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator<T>( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include <cmath> +#include <limits> + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString<Detail::Approx>( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + template<typename ExpressionT> + struct Matcher : SharedImpl<IShared> + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr<Matcher> clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + }; + + template<typename DerivedT, typename ExpressionT> + struct MatcherImpl : Matcher<ExpressionT> { + + virtual Ptr<Matcher<ExpressionT> > clone() const { + return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) ); + } + }; + + namespace Generic { + + template<typename ExpressionT> + class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher<ExpressionT> const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + }; + + template<typename ExpressionT> + class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher<ExpressionT> const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + }; + + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct Equals : MatcherImpl<Equals, std::string> { + Equals( std::string const& str ) : m_str( str ){} + Equals( Equals const& other ) : m_str( other.m_str ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_str == expr; + } + virtual std::string toString() const { + return "equals: \"" + m_str + "\""; + } + + std::string m_str; + }; + + struct Contains : MatcherImpl<Contains, std::string> { + Contains( std::string const& substr ) : m_substr( substr ){} + Contains( Contains const& other ) : m_substr( other.m_substr ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct StartsWith : MatcherImpl<StartsWith, std::string> { + StartsWith( std::string const& substr ) : m_substr( substr ){} + StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct EndsWith : MatcherImpl<EndsWith, std::string> { + EndsWith( std::string const& substr ) : m_substr( substr ){} + EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == expr.size() - m_substr.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template<typename ExpressionT> + inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2 ) { + return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ); + } + template<typename ExpressionT> + inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2, + Impl::Matcher<ExpressionT> const& m3 ) { + return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); + } + template<typename ExpressionT> + inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2 ) { + return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ); + } + template<typename ExpressionT> + inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2, + Impl::Matcher<ExpressionT> const& m3 ) { + return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str ) { + return Impl::StdString::Equals( str ); + } + inline Impl::StdString::Equals Equals( const char* str ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); + } + inline Impl::StdString::Contains Contains( std::string const& substr ) { + return Impl::StdString::Contains( substr ); + } + inline Impl::StdString::Contains Contains( const char* substr ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include <string> + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template<typename T> + class Option { + public: + Option() : nullableValue( NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != NULL; } + bool none() const { return nullableValue == NULL; } + + bool operator !() const { return nullableValue == NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option<TagAlias> find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include <string> +#include <set> + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set<std::string> const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set<std::string> tags; + std::set<std::string> lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr<ITestCase> test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import <objc/runtime.h> + +#include <string> + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl<ITestCase> { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template<typename MatcherT> + struct StringHolder : MatcherImpl<MatcherT, NSString*>{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder<Equals> { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder<Contains> { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder<StartsWith> { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder<EndsWith> { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_runner.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#include <string> +#include <vector> + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { + if( startsWith( m_name, "*" ) ) { + m_name = m_name.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_name, "*" ) ) { + m_name = m_name.substr( 0, m_name.size()-1 ); + m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); + } + } + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_name == toLower( testCase.name ); + case WildcardAtStart: + return endsWith( toLower( testCase.name ), m_name ); + case WildcardAtEnd: + return startsWith( toLower( testCase.name ), m_name ); + case WildcardAtBothEnds: + return contains( toLower( testCase.name ), m_name ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string m_name; + WildcardPosition m_wildcard; + }; + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr<Pattern> m_underlyingPattern; + }; + + struct Filter { + std::vector<Ptr<Pattern> > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector<Filter> m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern<TestSpec::NamePattern>(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern<TestSpec::NamePattern>(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern<TestSpec::NamePattern>(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern<TestSpec::NamePattern>(); + else if( m_mode == Tag && c == ']' ) + addPattern<TestSpec::TagPattern>(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template<typename T> + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr<TestSpec::Pattern> pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include <iostream> +#include <string> +#include <vector> + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual bool forceColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +#include <streambuf> + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + class Stream { + public: + Stream(); + Stream( std::streambuf* _streamBuf, bool _isOwned ); + void release(); + + std::streambuf* streamBuf; + + private: + bool isOwned; + }; + + std::ostream& cout(); + std::ostream& cerr(); +} + +#include <memory> +#include <vector> +#include <string> +#include <iostream> +#include <ctime> + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + forceColour( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool forceColour; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + + std::string reporterName; + std::string outputFilename; + std::string name; + std::string processName; + + std::vector<std::string> testsOrTags; + }; + + class Config : public SharedImpl<IConfig> { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + : m_os( Catch::cout().rdbuf() ) + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_os( Catch::cout().rdbuf() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + m_os.rdbuf( Catch::cout().rdbuf() ); + m_stream.release(); + } + + void setFilename( std::string const& filename ) { + m_data.outputFilename = filename; + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + void setStreamBuf( std::streambuf* buf ) { + m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); + } + + void useStream( std::string const& streamName ) { + Stream stream = createStream( streamName ); + setStreamBuf( stream.streamBuf ); + m_stream.release(); + m_stream = stream; + } + + std::string getReporterName() const { return m_data.reporterName; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_os; } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual bool forceColour() const { return m_data.forceColour; } + + private: + ConfigData m_data; + + Stream m_stream; + mutable std::ostream m_os; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include <string> +#include <vector> +#include <sstream> + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector<std::string>::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector<std::string> lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +#include <map> +#include <algorithm> +#include <stdexcept> +#include <memory> + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template<typename T> struct RemoveConstRef{ typedef T type; }; + template<typename T> struct RemoveConstRef<T&>{ typedef T type; }; + template<typename T> struct RemoveConstRef<T const&>{ typedef T type; }; + template<typename T> struct RemoveConstRef<T const>{ typedef T type; }; + + template<typename T> struct IsBool { static const bool value = false; }; + template<> struct IsBool<bool> { static const bool value = true; }; + + template<typename T> + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template<typename T> + inline void convertInto( bool, T& ) { + throw std::runtime_error( "Invalid conversion" ); + } + + template<typename ConfigT> + struct IArgFunction { + virtual ~IArgFunction() {} +# ifdef CATCH_CPP11_OR_GREATER + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +# endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template<typename ConfigT> + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != NULL; + } + private: + IArgFunction<ConfigT>* functionObj; + }; + + template<typename C> + struct NullBinder : IArgFunction<C>{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } + }; + + template<typename C, typename M> + struct BoundDataMember : IArgFunction<C>{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool<M>::value; } + virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template<typename C, typename M> + struct BoundUnaryMethod : IArgFunction<C>{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef<M>::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef<M>::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool<M>::value; } + virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template<typename C> + struct BoundNullaryMethod : IArgFunction<C>{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template<typename C> + struct BoundUnaryFunction : IArgFunction<C>{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template<typename C, typename T> + struct BoundBinaryFunction : IArgFunction<C>{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef<T>::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef<T>::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool<T>::value; } + virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template<typename ConfigT> + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction<ConfigT> boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector<std::string> shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template<typename ConfigT> + class CommandLine { + + struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {} + + using CommonArgProperties<ConfigT>::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + // NOTE: std::auto_ptr is deprecated in c++11/c++0x +#if defined(__cplusplus) && __cplusplus > 199711L + typedef std::unique_ptr<Arg> ArgAutoPtr; +#else + typedef std::auto_ptr<Arg> ArgAutoPtr; +#endif + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template<typename C, typename M> + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember<C,M>( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template<typename C> + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember<C,bool>( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template<typename C, typename M> + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template<typename C> + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template<typename C> + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template<typename C> + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template<typename C, typename T> + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder<ConfigT>() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template<typename C, typename M> + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember<C,M>( field ); + } + template<typename C, typename M> + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const * const * argv ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector<Parser::Token> tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + validate(); + std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + std::vector<Parser::Token> unusedTokens; + std::vector<std::string> errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + std::vector<Parser::Token> unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector<Parser::Token> unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector<Arg>::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction<ConfigT> m_boundProcessName; + std::vector<Arg> m_options; + std::map<int, Arg> m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include <fstream> + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast<unsigned int>( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast<Verbosity::Level>( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine<ConfigData> makeCommandLineParser() { + + using namespace Clara; + CommandLine<ConfigData> cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &ConfigData::reporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes/no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output" ) + .bind( &ConfigData::forceColour ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include <string> +#include <vector> +#include <sstream> + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector<std::string>::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector<std::string> lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include <string> +#include <ostream> +#include <map> +#include <assert.h> + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr<IConfig> const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr<IConfig> fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr<IConfig> m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template<typename T> + struct LazyStat : Option<T> { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option<T>::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option<T>::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector<MessageInfo> const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CPP11_OR_GREATER + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector<MessageInfo> infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CPP11_OR_GREATER + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CPP11_OR_GREATER + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CPP11_OR_GREATER + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CPP11_OR_GREATER + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map<std::string, IReporterFactory*> FactoryMap; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + }; + +} + +#include <limits> +#include <algorithm> + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector<TestCase> matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector<TestCase> matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set<std::string> spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map<std::string, TagInfo> tagCounts; + + std::vector<TestCase> matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option<std::size_t> list( Config const& config ) { + Option<std::size_t> listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_runner_impl.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include <map> +#include <string> +#include <assert.h> + +namespace Catch { +namespace SectionTracking { + + class TrackedSection { + + typedef std::map<std::string, TrackedSection> TrackedSections; + + public: + enum RunState { + NotStarted, + Executing, + ExecutingChildren, + Completed + }; + + TrackedSection( std::string const& name, TrackedSection* parent ) + : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + {} + + RunState runState() const { return m_runState; } + + TrackedSection* findChild( std::string const& childName ) { + TrackedSections::iterator it = m_children.find( childName ); + return it != m_children.end() + ? &it->second + : NULL; + } + TrackedSection* acquireChild( std::string const& childName ) { + if( TrackedSection* child = findChild( childName ) ) + return child; + m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); + return findChild( childName ); + } + void enter() { + if( m_runState == NotStarted ) + m_runState = Executing; + } + void leave() { + for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); + it != itEnd; + ++it ) + if( it->second.runState() != Completed ) { + m_runState = ExecutingChildren; + return; + } + m_runState = Completed; + } + TrackedSection* getParent() { + return m_parent; + } + bool hasChildren() const { + return !m_children.empty(); + } + + private: + std::string m_name; + RunState m_runState; + TrackedSections m_children; + TrackedSection* m_parent; + + }; + + class TestCaseTracker { + public: + TestCaseTracker( std::string const& testCaseName ) + : m_testCase( testCaseName, NULL ), + m_currentSection( &m_testCase ), + m_completedASectionThisRun( false ) + {} + + bool enterSection( std::string const& name ) { + TrackedSection* child = m_currentSection->acquireChild( name ); + if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) + return false; + + m_currentSection = child; + m_currentSection->enter(); + return true; + } + void leaveSection() { + m_currentSection->leave(); + m_currentSection = m_currentSection->getParent(); + assert( m_currentSection != NULL ); + m_completedASectionThisRun = true; + } + + bool currentSectionHasChildren() const { + return m_currentSection->hasChildren(); + } + bool isCompleted() const { + return m_testCase.runState() == TrackedSection::Completed; + } + + class Guard { + public: + Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { + m_tracker.enterTestCase(); + } + ~Guard() { + m_tracker.leaveTestCase(); + } + private: + Guard( Guard const& ); + void operator = ( Guard const& ); + TestCaseTracker& m_tracker; + }; + + private: + void enterTestCase() { + m_currentSection = &m_testCase; + m_completedASectionThisRun = false; + m_testCase.enter(); + } + void leaveTestCase() { + m_testCase.leave(); + } + + TrackedSection m_testCase; + TrackedSection* m_currentSection; + bool m_completedASectionThisRun; + }; + +} // namespace SectionTracking + +using SectionTracking::TestCaseTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include <signal.h> + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "<unknown signal>", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include <set> +#include <string> + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter ) + : m_runInfo( config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( NULL ), + m_config( config ), + m_reporter( reporter ), + m_prevRunner( m_context.getRunner() ), + m_prevResultCapture( m_context.getResultCapture() ), + m_prevConfig( m_context.getConfig() ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + m_context.setRunner( m_prevRunner ); + m_context.setConfig( NULL ); + m_context.setResultCapture( m_prevResultCapture ); + m_context.setConfig( m_prevConfig ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + m_testCaseTracker = TestCaseTracker( testInfo.name ); + + do { + do { + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isCompleted() && !aborting() ); + } + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = NULL; + m_testCaseTracker.reset(); + + return deltaTotals; + } + + Ptr<IConfig const> config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + if( !m_testCaseTracker->enterSection( oss.str() ) ) + return false; + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 || + !m_config->warnAboutMissingAssertions() || + m_testCaseTracker->currentSectionHasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { + if( std::uncaught_exception() ) { + m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); + return; + } + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + m_testCaseTracker->leaveSection(); + + m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + TestCaseTracker::Guard guard( *m_testCaseTracker ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + m_unfinishedSections.clear(); + } + + struct UnfinishedSections { + UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) + : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo info; + Counts prevAssertions; + double durationInSeconds; + }; + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + Option<TestCaseTracker> m_testCaseTracker; + AssertionResult m_lastResult; + + Ptr<IConfig const> m_config; + Totals m_totals; + Ptr<IStreamingReporter> m_reporter; + std::vector<MessageInfo> m_messages; + IRunner* m_prevRunner; + IResultCapture* m_prevResultCapture; + Ptr<IConfig const> m_prevConfig; + AssertionInfo m_lastAssertionInfo; + std::vector<UnfinishedSections> m_unfinishedSections; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _buildNumber, + char const* const _branchName ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + buildNumber( _buildNumber ), + branchName( _branchName ) + {} + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const buildNumber; + char const* const branchName; + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include <fstream> +#include <stdlib.h> +#include <limits> + +namespace Catch { + + class Runner { + + public: + Runner( Ptr<Config> const& config ) + : m_config( config ) + { + openStream(); + makeReporter(); + } + + Totals runTests() { + + RunContext context( m_config.get(), m_reporter ); + + Totals totals; + + context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + + TestSpec testSpec = m_config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector<TestCase> testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); + + int testsRunForGroup = 0; + for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + + if( context.aborting() ) + break; + + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); + } + } + std::vector<TestCase> skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector<TestCase>::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + + context.testGroupEnded( "all tests", totals, 1, 1 ); + return totals; + } + + private: + void openStream() { + // Open output file, if specified + if( !m_config->getFilename().empty() ) { + m_ofs.open( m_config->getFilename().c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << m_config->getFilename() << "'"; + throw std::domain_error( oss.str() ); + } + m_config->setStreamBuf( m_ofs.rdbuf() ); + } + } + void makeReporter() { + std::string reporterName = m_config->getReporterName().empty() + ? "console" + : m_config->getReporterName(); + + m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); + if( !m_reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + } + + private: + Ptr<Config> m_config; + std::ofstream m_ofs; + Ptr<IStreamingReporter> m_reporter; + std::set<TestCase> m_testsAlreadyRun; + }; + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " build " + << libraryVersion.buildNumber; + if( libraryVersion.branchName != std::string( "master" ) ) + Catch::cout() << " (" << libraryVersion.branchName << " branch)"; + Catch::cout() << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits<int>::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char* const argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + std::srand( m_configData.rngSeed ); + + Runner runner( m_config ); + + // Handle list request + if( Option<std::size_t> listed = list( config() ) ) + return static_cast<int>( *listed ); + + return static_cast<int>( runner.runTests().assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits<int>::max)(); + } + } + + Clara::CommandLine<ConfigData> const& cli() const { + return m_cli; + } + std::vector<Clara::Parser::Token> const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + + private: + Clara::CommandLine<ConfigData> m_cli; + std::vector<Clara::Parser::Token> m_unusedTokens; + ConfigData m_configData; + Ptr<Config> m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include <vector> +#include <set> +#include <sstream> +#include <iostream> +#include <algorithm> + +namespace Catch { + + class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i<j);} + }; + struct RandomNumberGenerator { + int operator()( int n ) const { return std::rand() % n; } + }; + + public: + TestRegistry() : m_unnamedCount( 0 ) {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + + if( m_functions.find( testCase ) == m_functions.end() ) { + m_functions.insert( testCase ); + m_functionsInOrder.push_back( testCase ); + if( !testCase.isHidden() ) + m_nonHiddenFunctions.push_back( testCase ); + } + else { + TestCase const& prev = *m_functions.find( testCase ); + { + Colour colourGuard( Colour::Red ); + Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + } + exit(1); + } + } + + virtual std::vector<TestCase> const& getAllTests() const { + return m_functionsInOrder; + } + + virtual std::vector<TestCase> const& getAllNonHiddenTests() const { + return m_nonHiddenFunctions; + } + + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const { + + for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); + if( includeTest != negated ) + matchingTestCases.push_back( *it ); + } + sortTests( config, matchingTestCases ); + } + + private: + + static void sortTests( IConfig const& config, std::vector<TestCase>& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } + std::set<TestCase> m_functions; + std::vector<TestCase> m_functionsInOrder; + std::vector<TestCase> m_nonHiddenFunctions; + size_t m_unnamedCount; + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl<ITestCase> { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + AutoReg::~AutoReg() {} + + void AutoReg::registerTestCase( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include <map> + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() { + deleteAllValues( m_factories ); + } + + virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + + FactoryMap const& getFactories() const { + return m_factories; + } + + private: + FactoryMap m_factories; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + throw; + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + throw; +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return tryTranslators( m_translators.begin() ); + } + } + + std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const { + if( it == m_translators.end() ) + return "Unknown exception"; + + try { + return (*it)->translate(); + } + catch(...) { + return tryTranslators( it+1 ); + } + } + + private: + std::vector<const IExceptionTranslator*> m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerTest( TestCase const& testInfo ) { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include <ostream> + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include <streambuf> + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include <stdexcept> +#include <cstdio> +#include <iostream> + +namespace Catch { + + template<typename WriterF, size_t bufferSize=256> + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast<char>( c ) ) ); + else + sputc( static_cast<char>( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + Stream::Stream() + : streamBuf( NULL ), isOwned( false ) + {} + + Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) + : streamBuf( _streamBuf ), isOwned( _isOwned ) + {} + + void Stream::release() { + if( isOwned ) { + delete streamBuf; + streamBuf = NULL; + isOwned = false; + } + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr<IConfig const> getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr<IConfig const> const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map<std::string, IGeneratorsForTest*>::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr<IConfig const> m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName; + }; + + namespace { + Context* currentContext = NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + Stream createStream( std::string const& streamName ) { + if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); + if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); + if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true ); + + throw std::domain_error( "Unknown stream: " + streamName ); + } + + void cleanUpContext() { + delete currentContext; + currentContext = NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include <AfxWin.h> +#else +#include <windows.h> +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalAttributes = csbiInfo.wAttributes; + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + } + HANDLE stdoutHandle; + WORD originalAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include <unistd.h> + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr<IConfig const> config = getCurrentContext().getConfig(); + return (config && config->forceColour()) || isatty(STDOUT_FILENO) + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = isDebuggerActive() + ? NoColourImpl::instance() + : platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include <vector> +#include <string> +#include <map> + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin(); + std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map<std::string, IGeneratorInfo*> m_generatorsByName; + std::vector<IGeneratorInfo*> m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set<std::string> tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set<std::string> const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + tags( _tags ), + lineInfo( _lineInfo ), + properties( None ) + { + std::ostringstream oss; + for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) ); + lcaseTags.insert( lcaseTag ); + } + tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + // These numbers are maintained by a script + Version libraryVersion( 1, 1, 1, "master" ); +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl<IStreamingReporter> + { + public: + LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr<IReporter> m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include <windows.h> +#else +#include <sys/time.h> +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) ); + QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,NULL); + return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast<unsigned int>(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast<unsigned int>(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) + getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include <iostream> + +#ifdef CATCH_PLATFORM_MAC + + #include <assert.h> + #include <stdbool.h> + #include <sys/types.h> + #include <unistd.h> + #include <sys/sysctl.h> + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + std::string unprintableString = "{?}"; + + namespace { + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast<int>( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast<unsigned char const *>(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast<unsigned>(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast<const char*>( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast<const wchar_t*>( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + if( value > 8192 ) + oss << "0x" << std::hex << value; + else + oss << value; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + if( value > 8192 ) + oss << "0x" << std::hex << value; + else + oss << value; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast<unsigned long>( value ) ); +} + +template<typename T> +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast<unsigned int>( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast<char>( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast<char>( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include <map> + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option<TagAlias> find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map<std::string, TagAlias> m_registry; + }; + +} // end namespace Catch + +#include <map> +#include <iostream> + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const { + std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option<TagAlias>(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include <cstring> + +namespace Catch { + + struct StreamingReporterBase : SharedImpl<IStreamingReporter> { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + + virtual ~StreamingReporterBase(); + + virtual void noMatchingTestCases( std::string const& ) {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr<IConfig> m_config; + std::ostream& stream; + + LazyStat<TestRunInfo> currentTestRunInfo; + LazyStat<GroupInfo> currentGroupInfo; + LazyStat<TestCaseInfo> currentTestCaseInfo; + + std::vector<SectionInfo> m_sectionStack; + }; + + struct CumulativeReporterBase : SharedImpl<IStreamingReporter> { + template<typename T, typename ChildNodeT> + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector<Ptr<ChildNodeT> > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr<SectionNode> const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector<Ptr<SectionNode> > ChildSections; + typedef std::vector<AssertionStats> Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr<SectionNode> const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node<TestCaseStats, SectionNode> TestCaseNode; + typedef Node<TestGroupStats, TestCaseNode> TestGroupNode; + typedef Node<TestRunStats, TestGroupNode> TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + ~CumulativeReporterBase(); + + virtual void testRunStarting( TestRunInfo const& ) {} + virtual void testGroupStarting( GroupInfo const& ) {} + + virtual void testCaseStarting( TestCaseInfo const& ) {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr<SectionNode> node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) { + Ptr<TestRunNode> node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) {} + + Ptr<IConfig> m_config; + std::ostream& stream; + std::vector<AssertionStats> m_assertions; + std::vector<std::vector<Ptr<SectionNode> > > m_sections; + std::vector<Ptr<TestCaseNode> > m_testCases; + std::vector<Ptr<TestGroupNode> > m_testGroups; + + std::vector<Ptr<TestRunNode> > m_testRuns; + + Ptr<SectionNode> m_rootSection; + Ptr<SectionNode> m_deepestSection; + std::vector<Ptr<SectionNode> > m_sectionStack; + + }; + + template<char C> + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template<typename T> + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template<typename T> + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include <sstream> +#include <string> +#include <vector> + +namespace Catch { + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template<typename T> + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + +//# ifndef CATCH_CPP11_OR_GREATER +// XmlWriter& operator = ( XmlWriter const& other ) { +// XmlWriter temp( other ); +// swap( temp ); +// return *this; +// } +//# else +// XmlWriter( XmlWriter const& ) = default; +// XmlWriter( XmlWriter && ) = default; +// XmlWriter& operator = ( XmlWriter const& ) = default; +// XmlWriter& operator = ( XmlWriter && ) = default; +//# endif +// +// void swap( XmlWriter& other ) { +// std::swap( m_tagIsOpen, other.m_tagIsOpen ); +// std::swap( m_needsNewline, other.m_needsNewline ); +// std::swap( m_tags, other.m_tags ); +// std::swap( m_indent, other.m_indent ); +// std::swap( m_os, other.m_os ); +// } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "</" << m_tags.back() << ">\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) { + stream() << " " << name << "=\""; + writeEncodedText( attribute ); + stream() << "\""; + } + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template<typename T> + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + if( !name.empty() ) + stream() << " " << name << "=\"" << attribute << "\""; + return *this; + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + writeEncodedText( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << "<!--" << text << "-->"; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + void writeEncodedText( std::string const& text ) { + static const char* charsToEncode = "<&\""; + std::string mtext = text; + std::string::size_type pos = mtext.find_first_of( charsToEncode ); + while( pos != std::string::npos ) { + stream() << mtext.substr( 0, pos ); + + switch( mtext[pos] ) { + case '<': + stream() << "<"; + break; + case '&': + stream() << "&"; + break; + case '\"': + stream() << """; + break; + } + mtext = mtext.substr( pos+1 ); + pos = mtext.find_first_of( charsToEncode ); + } + stream() << mtext; + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector<std::string> m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + {} + + virtual ~XmlReporter(); + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in <Info> tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include <assert.h> + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + {} + + ~JunitReporter(); + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector<MessageInfo>::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter(); + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector<MessageInfo> messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " b" + << libraryVersion.buildNumber; + if( libraryVersion.branchName != std::string( "master" ) ) + stream << " (" << libraryVersion.branchName << ")"; + stream << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector<SectionInfo>::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector<std::string> rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector<SummaryColumn> columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) { + for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector<MessageInfo>::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector<MessageInfo> messages; + std::vector<MessageInfo>::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * const argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( " Given: " desc, "" ) +#define WHEN( desc ) SECTION( " When: " desc, "" ) +#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) +#define THEN( desc ) SECTION( " Then: " desc, "" ) +#define AND_THEN( desc ) SECTION( " And: " desc, "" ) + +using Catch::Detail::Approx; + +// #included from: internal/catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/LICENSE b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/LICENSE new file mode 100755 index 0000000000000000000000000000000000000000..ca2bfe1a03ee5e391f51b1bc4de47114421eec98 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/LICENSE @@ -0,0 +1,55 @@ +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. diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/assertions.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/assertions.h new file mode 100755 index 0000000000000000000000000000000000000000..fbec7ae00e2425c8b5bea7e15a10f285e511f090 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/assertions.h @@ -0,0 +1,54 @@ +// 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_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include <stdlib.h> +#include <sstream> + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + std::ostringstream oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + std::ostringstream oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/autolink.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/autolink.h new file mode 100755 index 0000000000000000000000000000000000000000..6fcc8afac57c804bfb1689efd3f9fcdd612933e7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/autolink.h @@ -0,0 +1,25 @@ +// 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_AUTOLINK_H_INCLUDED +#define JSON_AUTOLINK_H_INCLUDED + +#include "config.h" + +#ifdef JSON_IN_CPPTL +#include <cpptl/cpptl_autolink.h> +#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 --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/config.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/config.h new file mode 100755 index 0000000000000000000000000000000000000000..7201ba7df8a00659b5a92771dd5366ea96fb2966 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/config.h @@ -0,0 +1,138 @@ +// 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 non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// 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 <cpptl/config.h> +#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) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#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) // MSVC +# if _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 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#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 diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/forwards.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/forwards.h new file mode 100755 index 0000000000000000000000000000000000000000..ccfe09abf4b8fd070622c84d8449cbf67ef4771d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/forwards.h @@ -0,0 +1,37 @@ +// 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; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/json-features.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/json-features.h new file mode 100755 index 0000000000000000000000000000000000000000..1bb7bb6148682777e2504cfb4bcf7816ffeabf99 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/json-features.h @@ -0,0 +1,57 @@ +// 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_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/json.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/json.h new file mode 100755 index 0000000000000000000000000000000000000000..113add4146391691faaa29344c4b76861e94be14 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/json.h @@ -0,0 +1,15 @@ +// 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_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED + +#include "autolink.h" +#include "json-features.h" +#include "reader.h" +#include "value.h" +#include "writer.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/reader.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/reader.h new file mode 100755 index 0000000000000000000000000000000000000000..8bc44ce188061c381c60b43b357262c076fe94a8 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/reader.h @@ -0,0 +1,402 @@ +// 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 "json-features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <deque> +#include <iosfwd> +#include <istream> +#include <stack> +#include <string> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { + public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + size_t offset_start; + size_t offset_limit; + std::string message; + }; + + /** \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 <a HREF="http://www.json.org">JSON</a> + * 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 <a HREF="http://www.json.org">JSON</a> + 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; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector<StructuredError> getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const std::string& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const std::string& message, + const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() 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<ErrorInfo> Errors; + + 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 decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, + 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& currentValue(); + 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<Value*> 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_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { + public: + virtual ~CharReader() {} + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + document. + * The document must be a UTF-8 encoded string containing the document to + read. + * + * \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 errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, + std::string* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + std::string errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { + public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See + StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an + object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() override; + + CharReader* newCharReader() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](std::string key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, std::istream&, + Value* root, std::string* errs); + +/** \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<<() +*/ +JSON_API std::istream& operator>>(std::istream&, Value&); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/value.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/value.h new file mode 100755 index 0000000000000000000000000000000000000000..1cfda07743412fa300ac26efc599c8f1fab6bf75 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/value.h @@ -0,0 +1,849 @@ +// 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 <string> +#include <vector> +#include <exception> + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include <map> +#else +#include <cpptl/smallmap.h> +#endif +#ifdef JSON_USE_CPPTL +#include <cpptl/forwards.h> +#endif + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(std::string const& msg); + ~Exception() throw() override; + char const* what() const throw() override; +protected: + std::string msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(std::string const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(std::string const& msg); +}; + +/// used internally +void throwRuntimeError(std::string const& msg); +/// used internally +void throwLogicError(std::string const& msg); + +/** \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<const char *> EnumMemberNames; +// typedef CppTL::AnyEnumerator<const Value &> 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) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a <a HREF="http://www.json.org">JSON</a> 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 resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain 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. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector<std::string> 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; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as 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; + +#if defined(JSON_HAS_INT64) + /// 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; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(CZString other); + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map<CZString, Value> ObjectValues; +#else + typedef CppTL::SmallMap<CZString, Value> ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#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); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \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. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value& operator=(Value other); + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + 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; ///< Embedded zeroes could cause you trouble! + std::string asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + 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 isInt64() const; + bool isUInt() const; + bool isUInt64() 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. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + 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. + /// \param key may contain embedded nulls. + Value& operator[](const std::string& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + 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 has 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. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const std::string& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \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 + /// \deprecated + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + Value removeMember(const std::string& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(std::string const& key, Value* removed); + /// Same as removeMember(std::string const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const std::string& key) const; + /// Same as isMember(std::string const& key)const + bool isMember(const char* begin, const char* end) 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 + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, 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(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(size_t start); + void setOffsetLimit(size_t limit); + size_t getOffsetStart() const; + size_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + 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_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + size_t start_; + size_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API 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 JSON_API 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<const PathArgument*> InArgs; + typedef std::vector<PathArgument> 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 base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + 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 other.computeDistance(*this); + } + + /// 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, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + std::string name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) 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: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +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(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +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(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/version.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/version.h new file mode 100755 index 0000000000000000000000000000000000000000..9df36d7cd1ec67f3e20ebddbcb6f1950c0cd9253 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/version.h @@ -0,0 +1,13 @@ +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "1.6.5" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 6 +# define JSONCPP_VERSION_PATCH 5 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#endif // JSON_VERSION_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/writer.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/writer.h new file mode 100755 index 0000000000000000000000000000000000000000..f94aa1fe775d4c3cf7c180ea11970677ee6696f0 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/include/writer.h @@ -0,0 +1,331 @@ +// 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 <vector> +#include <string> +#include <ostream> + +// Disable warning C4251: <data member>: <type> needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr<StreamWriter> const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + std::ostream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, std::ostream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr<Json::StreamWriter> writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "<anything>" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() override; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](std::string key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual std::string write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> 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 + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API FastWriter : public Writer { + +public: + FastWriter(); + ~FastWriter() override {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's Javascript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + std::string write(const Value& root) override; + +private: + void writeValue(const Value& value); + + std::string document_; + bool yamlCompatiblityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> 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() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() override {} + +public: // overridden from Writer + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + std::string write(const Value& root) override; + +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<std::string> ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> 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() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledStreamWriter { +public: + StyledStreamWriter(std::string indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> 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<std::string> ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#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>>() +JSON_API std::ostream& operator<<(std::ostream&, const Value& root); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_reader.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_reader.cpp new file mode 100755 index 0000000000000000000000000000000000000000..0453574c3f2eefa51eece9ee9d3b5dded1bda92d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_reader.cpp @@ -0,0 +1,2032 @@ +// Copyright 2007-2011 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/assertions.h" +#include "../include/reader.h" +#include "../include/value.h" +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <utility> +#include <cstdio> +#include <cassert> +#include <cstring> +#include <istream> +#include <sstream> +#include <memory> +#include <set> +#include <limits> + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +static int const stackLimit_g = 1000; +static int stackDepth_g = 0; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<CharReader> CharReaderPtr; +#else +typedef std::auto_ptr<CharReader> CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +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() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +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<char> begin(sin); + // std::istream_iterator<char> 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); + + stackDepth_g = 0; // Yes, this is bad coding, but options are limited. + 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() { + // This is a non-reentrant way to support a stackLimit. Terrible! + // But this deprecated class has a security problem: Bad input can + // cause a seg-fault. This seems like a fair, binary-compatible way + // to prevent the problem. + if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_g; + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_g; + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +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; +} + +static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { + std::string normalized; + normalized.reserve(end - begin); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const std::string& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +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 == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } +} + +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; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + 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) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // 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; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(c - '0'); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + std::string buffer(token.start_, token.end_); + std::istringstream is(buffer); + if (!(is >> value)) + return addError("'" + std::string(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + std::string decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + 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& current, + 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& current, + 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]; + snprintf(buffer, sizeof(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::vector<Reader::StructuredError> Reader::getStructuredErrors() const { + std::vector<Reader::StructuredError> allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const std::string& message) { + size_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { + size_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { + return !errors_.size(); +} + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + size_t offset_start; + size_t offset_limit; + std::string message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + std::string getFormattedErrorMessages() const; + std::vector<StructuredError> getStructuredErrors() const; + bool pushError(const Value& value, const std::string& message); + bool pushError(const Value& value, const std::string& message, const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + 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<ErrorInfo> Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + 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& currentValue(); + 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<Value*> Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + std::string commentsBefore_; + int stackDepth_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), + stackDepth_(0), + features_(features), collectComments_() { +} + +bool OurReader::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); + + stackDepth_ = 0; + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + 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 OurReader::readValue() { + if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_; + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits<double>::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_; + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::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 '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else continue + 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': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + 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 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + 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 OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::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 OurReader::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 +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const std::string& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& tokenStart) { + Token tokenName; + std::string name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + std::string msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, 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 OurReader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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 OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // 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; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(c - '0'); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, length); + buffer[length] = 0; + count = sscanf(buffer, format, &value); + } else { + std::string buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + std::string(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + std::string decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::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 OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + 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 OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + 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 +OurReader::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 OurReader::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 OurReader::addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::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 OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +std::string OurReader::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::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { + std::vector<OurReader::StructuredError> allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const std::string& message) { + size_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) { + size_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { + return !errors_.size(); +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + bool parse( + char const* beginDoc, char const* endDoc, + Value* root, std::string* errs) override { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set<std::string>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set<std::string> valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + std::string const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](std::string key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, std::istream& sin, + Value* root, std::string* errs) +{ + std::ostringstream ssin; + ssin << sin.rdbuf(); + std::string doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +std::istream& operator>>(std::istream& sin, Value& root) { + CharReaderBuilder b; + std::string errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_tool.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_tool.h new file mode 100755 index 0000000000000000000000000000000000000000..e65e51b4110c993438f370ece07b4f12db8e6ff4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_tool.h @@ -0,0 +1,87 @@ +// 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<char>(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast<char>(0x80 | (0x3f & cp)); + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast<char>(0x80 | (0x3f & cp)); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast<char>(0x80 | (0x3f & cp)); + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +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*& current) { + *--current = 0; + do { + *--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_value.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_value.cpp new file mode 100755 index 0000000000000000000000000000000000000000..616c809516da5f32ea3e140e35eeb4cbf920f668 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_value.cpp @@ -0,0 +1,1541 @@ +// Copyright 2011 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/assertions.h" +#include "../include/value.h" +#include "../include/writer.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <math.h> +#include <sstream> +#include <utility> +#include <cstring> +#include <cassert> +#ifdef JSON_USE_CPPTL +#include <cpptl/conststring.h> +#endif +#include <cstddef> // size_t +#include <algorithm> // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +const unsigned char& kNullRef = kNull[0]; +const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); +const Value& Value::nullRef = null; + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1); +} + +template <typename T> static inline double integerToDouble(T value) { + return static_cast<double>(value); +} + +template <typename T, typename U> +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** 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, + size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= (size_t)Value::maxInt) + length = Value::maxInt - 1; + + char* newString = static_cast<char*>(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U; + char* newString = static_cast<char*>(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast<unsigned*>(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast<unsigned>(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast<unsigned const*>(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +static inline void releaseStringValue(char* value) { free(value); } + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(std::string const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(std::string const& msg) + : Exception(msg) +{} +LogicError::LogicError(std::string const& msg) + : Exception(msg) +{} +void throwRuntimeError(std::string const& msg) +{ + throw RuntimeError(msg); +} +void throwLogicError(std::string const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) {} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) + : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_) { + storage_.policy_ = (other.cstr_ + ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast<DuplicationPolicy>(other.storage_.policy_)); + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) + releaseStringValue(const_cast<char*>(cstr_)); +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(CZString other) { + swap(other); + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// 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 vtype) { + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); +} + +Value::Value(const std::string& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast<char*>(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0), start_(other.start_), limit_(other.limit_) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + 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_, strlen(otherComment.comment_)); + } + } +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releaseStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + if (comments_) + delete[] comments_; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(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 & 0x1; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +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: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + 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_); + } + 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: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +std::string Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return std::string(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#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 intValue: + return static_cast<double>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<double>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast<float>(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast<float>(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast<float>(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString() == "") || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// 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; + 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()); + } + 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_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + 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); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + 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, nullRef); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullRef; + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullRef; + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(cend-key), 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, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullRef ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullRef; + return *found; +} +Value const& Value::operator[](std::string const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullRef; + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const std::string& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullRef; + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(std::string const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(std::string const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullRef; + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const std::string& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(std::string const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + 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.data(), + (*it).first.length())); + } + 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<const CZString &>() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type<const Value &>() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif +} + +bool Value::isDouble() const { return type_ == realValue || isIntegral(); } + +bool Value::isNumeric() const { return isIntegral() || isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const std::string& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), 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 ""; +} + +void Value::setOffsetStart(size_t start) { start_ = start; } + +void Value::setOffsetLimit(size_t limit) { limit_ = limit; } + +size_t Value::getOffsetStart() const { return start_; } + +size_t Value::getOffsetLimit() const { return limit_; } + +std::string Value::toStyledString() const { + StyledWriter writer; + return writer.write(*this); +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const std::string& key) + : key_(key.c_str()), index_(), 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::nullRef) { + // 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::nullRef) + 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 diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_valueiterator.inl b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_valueiterator.inl new file mode 100755 index 0000000000000000000000000000000000000000..ec9c85127a7c1357918ff96bb459950dacb0dee2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_valueiterator.inl @@ -0,0 +1,167 @@ +// 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() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - 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 +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +std::string ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return std::string(); + return std::string(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_writer.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_writer.cpp new file mode 100755 index 0000000000000000000000000000000000000000..0751b067ce6291e67508d7fc1173ff6e611b1724 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/dependencies/jsoncpp/src/json_writer.cpp @@ -0,0 +1,1214 @@ +// Copyright 2011 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/writer.h" +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <iomanip> +#include <memory> +#include <sstream> +#include <utility> +#include <set> +#include <cassert> +#include <cstring> +#include <cstdio> + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include <float.h> +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) +#include <ieeefp.h> +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include <math.h> +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include <math.h> +#define isfinite finite +#endif +#endif +#else +#include <cmath> +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif + +#if defined(__BORLANDC__) +#include <float.h> +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<StreamWriter> StreamWriterPtr; +#else +typedef std::auto_ptr<StreamWriter> StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +std::string valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), 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, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} + +std::string valueToString(double value) { return valueToString(value, false, 17); } + +std::string valueToString(bool value) { return value ? "true" : "false"; } + +std::string valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // 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 </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if (isControlCharacter(*c)) { + std::ostringstream oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static std::string valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + 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 = + length * 2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++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 </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if ((isControlCharacter(*c)) || (*c == 0)) { + std::ostringstream oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +std::string FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + 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: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); + 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_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +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: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 = ((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; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + 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_ += "\n"; + writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(std::string indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(std::ostream& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + 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: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + 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 = ((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; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + 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() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const std::string& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +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; + + if (!indented_) writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + std::string const& indentation, + CommentStyle::Enum cs, + std::string const& colonSymbol, + std::string const& nullSymbol, + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, std::ostream* sout) override; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(std::string const& value); + void writeIndent(); + void writeWithIndent(std::string const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector<std::string> ChildValues; + + ChildValues childValues_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + CommentStyle::Enum cs_; + std::string colonSymbol_; + std::string nullSymbol_; + std::string endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + std::string const& indentation, + CommentStyle::Enum cs, + std::string const& colonSymbol, + std::string const& nullSymbol, + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + 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 (;;) { + std::string const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ", "; + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + 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; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(std::string const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + std::string indentation = settings_["indentation"].asString(); + std::string cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + std::string colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + std::string nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + std::string endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set<std::string>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set<std::string> valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + std::string const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](std::string key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +std::string writeString(StreamWriter::Factory const& builder, Value const& root) { + std::ostringstream sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +std::ostream& operator<<(std::ostream& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/Doxyfile b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..b76bccdc9eebe91bcb7abd6672ecd6a14dbd2cbf --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/Doxyfile @@ -0,0 +1,2401 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "XMM - Probabilistic Models for Motion Recognition and Mapping" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.0-beta + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = doc-misc/xmm_featured.jpg + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./ + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = DEVDOC + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = doc-misc/XmmDoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../src/ \ + ../src/core/common \ + ../src/core/trainingset \ + ../src/core/model \ + ../src/core/distributions \ + ../src/models/kmeans \ + ../src/models/gmm \ + ../src/models/hmm \ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.hpp + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = doc-misc + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = doc-misc + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = doc-misc/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = doc-misc/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = doc-misc/jdoxygen.css + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = doc-misc/jtabs.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = SWIGPYTHON USE_ARMA + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/Doxyfile-dot b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/Doxyfile-dot new file mode 100644 index 0000000000000000000000000000000000000000..8bd04ce77be9d5f1f2ae1684967c2d6c854cf4f3 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/Doxyfile-dot @@ -0,0 +1,2434 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "XMM - Probabilistic Models for Motion Recognition and Mapping" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.0-beta + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = doc-misc/xmm_featured.jpg + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./ + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = DEVDOC + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = doc-misc/XmmDoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../src/ \ + ../src/core/common \ + ../src/core/trainingset \ + ../src/core/model \ + ../src/core/distributions \ + ../src/models/kmeans \ + ../src/models/gmm \ + ../src/models/hmm \ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = doc-misc + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = doc-misc + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = doc-misc/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = doc-misc/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = doc-misc/jdoxygen.css + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = doc-misc/jtabs.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = SWIGPYTHON + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/QuickStart_Python.html b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/QuickStart_Python.html new file mode 100644 index 0000000000000000000000000000000000000000..24b9938fd3b1eb7ef3d2743add5a68a708b8b99b --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/QuickStart_Python.html @@ -0,0 +1,2086 @@ +<!DOCTYPE html> +<html> +<head><meta charset="utf-8" /> +<title>QuickStart_Python</title> + +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> + +<style type="text/css"> + /*! +* +* Twitter Bootstrap +* +*//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0;vertical-align:middle}svg:not(:root){overflow:hidden}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../components/bootstrap/fonts/glyphicons-halflings-regular.eot);src:url(../components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix)format('embedded-opentype'),url(../components/bootstrap/fonts/glyphicons-halflings-regular.woff2)format('woff2'),url(../components/bootstrap/fonts/glyphicons-halflings-regular.woff)format('woff'),url(../components/bootstrap/fonts/glyphicons-halflings-regular.ttf)format('truetype'),url(../components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular)format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before,.glyphicon-btc:before,.glyphicon-xbt:before{content:"\e227"}.glyphicon-jpy:before,.glyphicon-yen:before{content:"\00a5"}.glyphicon-rub:before,.glyphicon-ruble:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:1.42857143;color:#000;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}figure{margin:0}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:3px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:2px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:18px;margin-bottom:18px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:18px;margin-bottom:9px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:9px;margin-bottom:9px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:33px}.h2,h2{font-size:27px}.h3,h3{font-size:23px}.h4,h4{font-size:17px}.h5,h5{font-size:13px}.h6,h6{font-size:12px}p{margin:0 0 9px}.lead{margin-bottom:18px;font-size:14px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:19.5px}}.small,small{font-size:92%}.mark,mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:8px;margin:36px 0 18px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:9px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:18px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:541px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:9px 18px;margin:0 0 18px;font-size:inherit;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:18px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:monospace}code{padding:2px 4px;font-size:90%;background-color:#f9f2f4;border-radius:2px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:1px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;box-shadow:none}pre{display:block;padding:8.5px;margin:0 0 9px;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:2px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:0;padding-right:0}@media (min-width:768px){.container{width:768px}}@media (min-width:992px){.container{width:940px}}@media (min-width:1200px){.container{width:1140px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:0;padding-right:0}.row{margin-left:0;margin-right:0}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:0;padding-right:0}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:18px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:13.5px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:19.5px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{display:block;padding-top:7px;font-size:13px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:32px;padding:6px 12px;font-size:13px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:2px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:32px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:45px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:18px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px \9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:31px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:1px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:1px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;min-height:30px}.input-lg{height:45px;padding:10px 16px;font-size:17px;line-height:1.3333333;border-radius:3px}select.input-lg{height:45px;line-height:45px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:45px;padding:10px 16px;font-size:17px;line-height:1.3333333;border-radius:3px}select.form-group-lg .form-control{height:45px;line-height:45px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:45px;padding:10px 16px;font-size:17px;line-height:1.3333333;min-height:35px}.has-feedback{position:relative}.has-feedback .form-control{padding-right:40px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:32px;height:32px;line-height:32px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:45px;height:45px;line-height:45px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:23px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#404040}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:25px}.form-horizontal .form-group{margin-left:0;margin-right:0}.form-horizontal .has-feedback .form-control-feedback{right:0}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}.form-horizontal .form-group-lg .control-label{padding-top:14.33px}.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:13px;line-height:1.42857143;border-radius:2px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:400;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:17px;line-height:1.3333333;border-radius:3px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:1px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:1px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:13px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:2px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:8px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#337ab7}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:541px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:2px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:2px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:17px;line-height:1.3333333;border-radius:3px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:1px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:13px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:2px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:1px}.input-group-addon.input-lg{padding:10px 16px;font-size:17px;border-radius:3px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:8px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:2px 2px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px;margin-right:0;border-radius:2px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:2px 2px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:2px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:2px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:2px 2px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:30px;margin-bottom:18px;border:1px solid transparent}.navbar-collapse{overflow-x:visible;padding-right:0;padding-left:0;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:540px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-static-top{z-index:1000;border-width:0 0 1px}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:541px){.navbar{border-radius:2px}.navbar-header{float:left}.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:6px 0;font-size:17px;line-height:18px;height:30px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}.navbar-toggle{position:relative;float:right;margin-right:0;padding:9px 10px;margin-top:-2px;margin-bottom:-2px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:2px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:541px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:0}.navbar-toggle{display:none}}.navbar-nav{margin:3px 0}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:18px}@media (max-width:540px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:18px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:541px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:6px;padding-bottom:6px}}.navbar-form{padding:10px 0;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:-1px 0}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:540px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:2px 2px 0 0}.navbar-btn{margin-top:-1px;margin-bottom:-1px}.navbar-btn.btn-sm{margin-top:0;margin-bottom:0}.navbar-btn.btn-xs{margin-top:4px;margin-bottom:4px}.navbar-text{margin-top:6px;margin-bottom:6px}@media (min-width:541px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-text{float:left;margin-left:0;margin-right:0}.navbar-left{float:left!important;float:left}.navbar-right{float:right!important;float:right;margin-right:0}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#e7e7e7;color:#555}@media (max-width:540px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#080808;color:#fff}@media (max-width:540px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:18px;list-style:none;background-color:#f5f5f5;border-radius:2px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#5e5e5e}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:18px 0;border-radius:2px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;color:#337ab7;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:2px;border-top-left-radius:2px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:2px;border-top-right-radius:2px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:17px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:1px;border-top-left-radius:1px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:1px;border-top-right-radius:1px}.pager{padding-left:0;margin:18px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:20px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:3px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron .h1,.jumbotron h1{font-size:58.5px}}.thumbnail{display:block;padding:4px;margin-bottom:18px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:2px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-left:auto;margin-right:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#000}.alert{padding:15px;margin-bottom:18px;border:1px solid transparent;border-radius:2px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f5f5f5;border-radius:2px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:18px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:2px;border-top-left-radius:2px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:2px;border-bottom-left-radius:2px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{text-decoration:none;color:#555;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#eee;color:#777;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:18px;background-color:#fff;border:1px solid transparent;border-radius:2px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:1px;border-top-left-radius:1px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:15px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:1px;border-bottom-left-radius:1px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:1px;border-top-left-radius:1px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:1px;border-bottom-left-radius:1px}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-left:15px;padding-right:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-right-radius:1px;border-top-left-radius:1px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:1px;border-top-right-radius:1px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:1px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:1px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:1px;border-bottom-left-radius:1px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:1px;border-bottom-right-radius:1px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:1px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:1px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:18px}.panel-group .panel{margin-bottom:0;border-radius:2px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:2px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:3px}.well-sm{padding:9px;border-radius:1px}.close{float:right;font-size:19.5px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:3px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.43px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:2px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:400;line-height:1.42857143;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:3px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:13px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:2px 2px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-moz-transition:-moz-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;-moz-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:focus,.carousel-control:hover{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:transparent}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.item_buttons:after,.item_buttons:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{content:" ";display:table}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.item_buttons:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}.visible-xs-block{display:block!important}.visible-xs-inline{display:inline!important}.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}.visible-sm-block{display:block!important}.visible-sm-inline{display:inline!important}.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}.visible-md-block{display:block!important}.visible-md-inline{display:inline!important}.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}.visible-lg-block{display:block!important}.visible-lg-inline{display:inline!important}.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}.hidden-print{display:none!important}}/*! +* +* Font Awesome +* +*//*! + * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url(../components/font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0);src:url(../components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0)format('embedded-opentype'),url(../components/font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0)format('woff'),url(../components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0)format('truetype'),url(../components/font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular)format('svg');font-weight:400;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}/*! +* +* IPython base +* +*/.modal.fade .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}code{color:#000}pre{font-size:inherit;line-height:inherit}label{font-weight:400}.border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}.corner-all{border-radius:2px}.no-padding{padding:0}.hbox{display:-webkit-box;-webkit-box-orient:horizontal;display:-moz-box;-moz-box-orient:horizontal;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}.vbox{display:-webkit-box;-webkit-box-orient:vertical;display:-moz-box;-moz-box-orient:vertical;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}.vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}.hbox.reverse,.reverse,.vbox.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}.box-flex0,.hbox.box-flex0,.vbox.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}.box-flex1,.hbox.box-flex1,.vbox.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.box-flex,.hbox.box-flex,.vbox.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.box-flex2,.hbox.box-flex2,.vbox.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}.box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}.box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}.hbox.start,.start,.vbox.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}.end,.hbox.end,.vbox.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}.center,.hbox.center,.vbox.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}.baseline,.hbox.baseline,.vbox.baseline{-webkit-box-pack:baseline;-moz-box-pack:baseline;box-pack:baseline;justify-content:baseline}.hbox.stretch,.stretch,.vbox.stretch{-webkit-box-pack:stretch;-moz-box-pack:stretch;box-pack:stretch;justify-content:stretch}.align-start,.hbox.align-start,.vbox.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}.align-end,.hbox.align-end,.vbox.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}.align-center,.hbox.align-center,.vbox.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}.align-baseline,.hbox.align-baseline,.vbox.align-baseline{-webkit-box-align:baseline;-moz-box-align:baseline;box-align:baseline;align-items:baseline}.align-stretch,.hbox.align-stretch,.vbox.align-stretch{-webkit-box-align:stretch;-moz-box-align:stretch;box-align:stretch;align-items:stretch}div.error{margin:2em;text-align:center}div.error>h1{font-size:500%;line-height:normal}div.error>p{font-size:200%;line-height:normal}div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}body{position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}#header{display:none;background-color:#fff;position:relative;z-index:100}#header #header-container{padding-bottom:5px;padding-top:5px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}#header .header-bar{width:100%;height:1px;background:#e7e7e7;margin-bottom:-1px}#header-spacer{width:100%;visibility:hidden}@media print{#header{display:none!important}#header-spacer{display:none}}#ipython_notebook{padding-left:0;padding-top:1px;padding-bottom:1px}@media (max-width:991px){#ipython_notebook{margin-left:10px}}#noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:red;font-weight:700}#ipython_notebook img{height:28px}#site{width:100%;display:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;overflow:auto}@media print{#site{height:auto!important}}.ui-button .ui-button-text{padding:.2em .8em;font-size:77%}input.ui-button{padding:.3em .9em}span#login_widget{float:right}#logout,span#login_widget>.button{color:#333;background-color:#fff;border-color:#ccc}#logout.active,#logout.focus,#logout:active,#logout:focus,#logout:hover,.open>.dropdown-toggle#logout,.open>.dropdown-togglespan#login_widget>.button,span#login_widget>.button.active,span#login_widget>.button.focus,span#login_widget>.button:active,span#login_widget>.button:focus,span#login_widget>.button:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}#logout.active,#logout:active,.open>.dropdown-toggle#logout,.open>.dropdown-togglespan#login_widget>.button,span#login_widget>.button.active,span#login_widget>.button:active{background-image:none}#logout.disabled,#logout.disabled.active,#logout.disabled.focus,#logout.disabled:active,#logout.disabled:focus,#logout.disabled:hover,#logout[disabled],#logout[disabled].active,#logout[disabled].focus,#logout[disabled]:active,#logout[disabled]:focus,#logout[disabled]:hover,fieldset[disabled] #logout,fieldset[disabled] #logout.active,fieldset[disabled] #logout.focus,fieldset[disabled] #logout:active,fieldset[disabled] #logout:focus,fieldset[disabled] #logout:hover,fieldset[disabled] span#login_widget>.button,fieldset[disabled] span#login_widget>.button.active,fieldset[disabled] span#login_widget>.button.focus,fieldset[disabled] span#login_widget>.button:active,fieldset[disabled] span#login_widget>.button:focus,fieldset[disabled] span#login_widget>.button:hover,span#login_widget>.button.disabled,span#login_widget>.button.disabled.active,span#login_widget>.button.disabled.focus,span#login_widget>.button.disabled:active,span#login_widget>.button.disabled:focus,span#login_widget>.button.disabled:hover,span#login_widget>.button[disabled],span#login_widget>.button[disabled].active,span#login_widget>.button[disabled].focus,span#login_widget>.button[disabled]:active,span#login_widget>.button[disabled]:focus,span#login_widget>.button[disabled]:hover{background-color:#fff;border-color:#ccc}#logout .badge,span#login_widget>.button .badge{color:#fff;background-color:#333}.nav-header{text-transform:none}#header>span{margin-top:10px}.modal_stretch .modal-dialog{display:-webkit-box;-webkit-box-orient:vertical;display:-moz-box;-moz-box-orient:vertical;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;min-height:80vh}.modal_stretch .modal-dialog .modal-body{max-height:calc(100vh - 200px);overflow:auto;flex:1}@media (min-width:768px){.modal .modal-dialog{width:700px}select.form-control{margin-left:12px;margin-right:12px}}/*! +* +* IPython auth +* +*/.center-nav{display:inline-block;margin-bottom:-4px}/*! +* +* IPython tree view +* +*/.alternate_upload{background-color:none;display:inline}.alternate_upload.form{padding:0;margin:0}.alternate_upload input.fileinput{text-align:center;vertical-align:middle;display:inline;opacity:0;z-index:2;width:12ex;margin-right:-12ex}.alternate_upload .btn-upload{height:22px}ul#tabs{margin-bottom:4px}ul#tabs a{padding-top:6px;padding-bottom:4px}ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}ul.breadcrumb span{color:#5e5e5e}.list_toolbar{padding:4px 0;vertical-align:middle}.list_toolbar .tree-buttons{padding-top:1px}.dynamic-buttons{padding-top:3px;display:inline-block}.list_toolbar [class*=span]{min-height:24px}.list_header{font-weight:700;background-color:#eee}.list_placeholder{font-weight:700;padding:4px 7px}.list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ddd;border-radius:2px}.list_container>div{border-bottom:1px solid #ddd}.list_container>div:hover .list-item{background-color:red}.list_container>div:last-child{border:none}.list_item:hover .list_item{background-color:#ddd}.list_item a{text-decoration:none}.list_item:hover{background-color:#fafafa}.action_col{text-align:right}.list_header>div,.list_item>div{line-height:22px;padding:4px 7px}.list_header>div input,.list_item>div input{margin-right:7px;margin-left:14px;vertical-align:baseline;line-height:22px;position:relative;top:-1px}.list_header>div .item_link,.list_item>div .item_link{margin-left:-1px;vertical-align:baseline;line-height:22px}.new-file input[type=checkbox]{visibility:hidden}.item_name{line-height:22px;height:24px}.item_icon{font-size:14px;color:#5e5e5e;margin-right:7px;margin-left:7px;line-height:22px;vertical-align:baseline}.item_buttons{line-height:1em;margin-left:-5px}.item_buttons .btn-group,.item_buttons .input-group{float:left}.item_buttons>.btn,.item_buttons>.btn-group,.item_buttons>.input-group{margin-left:5px}.item_buttons .btn{min-width:13ex}.item_buttons .running-indicator{padding-top:4px;color:#5cb85c}.toolbar_info{height:24px;line-height:24px}input.engine_num_input,input.nbname_input{padding-top:3px;padding-bottom:3px;height:22px;line-height:14px;margin:0}input.engine_num_input{width:60px}.highlight_text{color:#00f}#project_name{display:inline-block;padding-left:7px;margin-left:-2px}#project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:700}#tree-selector{padding-right:0}#button-select-all{min-width:50px}#select-all{margin-left:7px;margin-right:2px}.menu_icon{margin-right:2px}.tab-content .row{margin-left:0;margin-right:0}.folder_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f114"}.folder_icon:before.pull-left{margin-right:.3em}.folder_icon:before.pull-right{margin-left:.3em}.notebook_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f02d";position:relative;top:-1px}.notebook_icon:before.pull-left{margin-right:.3em}.notebook_icon:before.pull-right{margin-left:.3em}.running_notebook_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f02d";position:relative;top:-1px;color:#5cb85c}.running_notebook_icon:before.pull-left{margin-right:.3em}.running_notebook_icon:before.pull-right{margin-left:.3em}.file_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f016";position:relative;top:-2px}.file_icon:before.pull-left{margin-right:.3em}.file_icon:before.pull-right{margin-left:.3em}#notebook_toolbar .pull-right{padding-top:0;margin-right:-1px}ul#new-menu{left:auto;right:0}.kernel-menu-icon{padding-right:12px;width:24px;content:"\f096"}.kernel-menu-icon:before{content:"\f096"}.kernel-menu-icon-current:before{content:"\f00c"}#tab_content{padding-top:20px}#running .panel-group .panel{margin-top:3px;margin-bottom:1em}#running .panel-group .panel .panel-heading{background-color:#eee;line-height:22px;padding:4px 7px}#running .panel-group .panel .panel-heading a:focus,#running .panel-group .panel .panel-heading a:hover{text-decoration:none}#running .panel-group .panel .panel-body{padding:0}#running .panel-group .panel .panel-body .list_container{margin-top:0;margin-bottom:0;border:0;border-radius:0}#running .panel-group .panel .panel-body .list_container .list_item{border-bottom:1px solid #ddd}#running .panel-group .panel .panel-body .list_container .list_item:last-child{border-bottom:0}.delete-button,.duplicate-button,.rename-button,.shutdown-button{display:none}.dynamic-instructions{display:inline-block;padding-top:4px}/*! +* +* IPython text editor webapp +* +*/.selected-keymap i.fa{padding:0 5px}.selected-keymap i.fa:before{content:"\f00c"}#mode-menu{overflow:auto;max-height:20em}.edit_app #header{-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}.edit_app #menubar .navbar{margin-bottom:-1px}.dirty-indicator{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;width:20px}.dirty-indicator.pull-left{margin-right:.3em}.dirty-indicator.pull-right{margin-left:.3em}.dirty-indicator-dirty{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;width:20px}.dirty-indicator-dirty.pull-left{margin-right:.3em}.dirty-indicator-dirty.pull-right{margin-left:.3em}.dirty-indicator-clean{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;width:20px}.dirty-indicator-clean.pull-left{margin-right:.3em}.dirty-indicator-clean.pull-right{margin-left:.3em}.dirty-indicator-clean:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f00c"}.dirty-indicator-clean:before.pull-left{margin-right:.3em}.dirty-indicator-clean:before.pull-right{margin-left:.3em}#filename{font-size:16pt;display:table;padding:0 5px}#current-mode{padding-left:5px;padding-right:5px}#texteditor-backdrop{padding-top:20px;padding-bottom:20px}@media not print{#texteditor-backdrop{background-color:#eee}}@media print{#texteditor-backdrop #texteditor-container .CodeMirror-gutter,#texteditor-backdrop #texteditor-container .CodeMirror-gutters{background-color:#fff}}@media not print{#texteditor-backdrop #texteditor-container .CodeMirror-gutter,#texteditor-backdrop #texteditor-container .CodeMirror-gutters{background-color:#fff}#texteditor-backdrop #texteditor-container{padding:0;background-color:#fff;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}}/*! +* +* IPython notebook +* +*/.ansibold{font-weight:700}.ansiblack{color:#000}.ansired{color:#8b0000}.ansigreen{color:#006400}.ansiyellow{color:#c4a000}.ansiblue{color:#00008b}.ansipurple{color:#9400d3}.ansicyan{color:#4682b4}.ansigray{color:gray}.ansibgblack{background-color:#000}.ansibgred{background-color:red}.ansibggreen{background-color:green}.ansibgyellow{background-color:#ff0}.ansibgblue{background-color:#00f}.ansibgpurple{background-color:#ff00ff}.ansibgcyan{background-color:#0ff}.ansibggray{background-color:gray}div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;display:-moz-box;-moz-box-orient:vertical;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;border-radius:2px;box-sizing:border-box;-moz-box-sizing:border-box;border-width:thin;border-style:solid;width:100%;padding:5px;margin:0;outline:0}div.cell.selected{border-color:#ababab}@media print{div.cell.selected{border-color:transparent}}.edit_mode div.cell.selected{border-color:green}.prompt{min-width:14ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;display:-moz-box;-moz-box-orient:vertical;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}@-moz-document url-prefix(){div.inner_cell{overflow-x:hidden}}div.input_area{border:1px solid #cfcfcf;border-radius:2px;background:#f7f7f7;line-height:1.21429em}div.prompt:empty{padding-top:0;padding-bottom:0}div.unrecognized_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;display:-moz-box;-moz-box-orient:horizontal;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.unrecognized_cell .inner_cell{border-radius:2px;padding:5px;font-weight:700;color:red;border:1px solid #cfcfcf;background:#eaeaea}div.unrecognized_cell .inner_cell a,div.unrecognized_cell .inner_cell a:hover{color:inherit;text-decoration:none}@media (max-width:540px){.prompt{text-align:left}div.unrecognized_cell>div.prompt{display:none}}div.code_cell{}div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;display:-moz-box;-moz-box-orient:horizontal;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}@media (max-width:540px){div.input{-webkit-box-orient:vertical;-moz-box-orient:vertical;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:navy;border-top:1px solid transparent}div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}div.input_area>div.highlight>pre{margin:0;border:none;padding:0;background-color:transparent}.CodeMirror{line-height:1.21429em;font-size:14px;height:auto;background:0 0}.CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}.CodeMirror-lines{padding:.4em}.CodeMirror-linenumber{padding:0 8px 0 4px}.CodeMirror-gutters{border-bottom-left-radius:2px;border-top-left-radius:2px}.CodeMirror pre{padding:0;border:0;border-radius:0}.highlight-base,.highlight-variable{color:#000}.highlight-variable-2{color:#1a1a1a}.highlight-variable-3{color:#333}.highlight-string{color:#BA2121}.highlight-comment{color:#408080;font-style:italic}.highlight-number{color:#080}.highlight-atom{color:#88F}.highlight-keyword{color:green;font-weight:700}.highlight-builtin{color:green}.highlight-error{color:red}.highlight-operator{color:#A2F;font-weight:700}.highlight-meta{color:#A2F}.highlight-def{color:#00f}.highlight-string-2{color:#f50}.highlight-qualifier{color:#555}.highlight-bracket{color:#997}.highlight-tag{color:#170}.highlight-attribute{color:#00c}.highlight-header{color:#00f}.highlight-quote{color:#090}.highlight-link{color:#00c}.cm-s-ipython span.cm-keyword{color:green;font-weight:700}.cm-s-ipython span.cm-atom{color:#88F}.cm-s-ipython span.cm-number{color:#080}.cm-s-ipython span.cm-def{color:#00f}.cm-s-ipython span.cm-variable{color:#000}.cm-s-ipython span.cm-operator{color:#A2F;font-weight:700}.cm-s-ipython span.cm-variable-2{color:#1a1a1a}.cm-s-ipython span.cm-variable-3{color:#333}.cm-s-ipython span.cm-comment{color:#408080;font-style:italic}.cm-s-ipython span.cm-string{color:#BA2121}.cm-s-ipython span.cm-string-2{color:#f50}.cm-s-ipython span.cm-meta{color:#A2F}.cm-s-ipython span.cm-qualifier{color:#555}.cm-s-ipython span.cm-builtin{color:green}.cm-s-ipython span.cm-bracket{color:#997}.cm-s-ipython span.cm-tag{color:#170}.cm-s-ipython span.cm-attribute{color:#00c}.cm-s-ipython span.cm-header{color:#00f}.cm-s-ipython span.cm-quote{color:#090}.cm-s-ipython span.cm-link{color:#00c}.cm-s-ipython span.cm-error{color:red}.cm-s-ipython span.cm-tab{background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=')right no-repeat}div.output_wrapper{display:-webkit-box;-webkit-box-align:stretch;display:-moz-box;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;z-index:1}div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:2px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,.8);box-shadow:inset 0 2px 8px rgba(0,0,0,.8);display:block}div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;display:-moz-box;-moz-box-orient:vertical;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:2px}div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,.5)}div.output_prompt{color:#8b0000}div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;display:-moz-box;-moz-box-orient:horizontal;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left!important}div.output_area .rendered_html img,div.output_area .rendered_html table{margin-left:0;margin-right:0}div.output_area img,div.output_area svg{max-width:100%;height:auto}div.output_area img.unconfined,div.output_area svg.unconfined{max-width:none}.output{display:-webkit-box;-webkit-box-orient:vertical;display:-moz-box;-moz-box-orient:vertical;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}@media (max-width:540px){div.output_area{-webkit-box-orient:vertical;-moz-box-orient:vertical;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}}div.output_area pre{margin:0;padding:0;border:0;vertical-align:baseline;color:#000;background-color:transparent;border-radius:0}div.output_subarea{overflow-x:auto;padding:.4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1;max-width:calc(100% - 14ex)}div.output_text{text-align:left;color:#000;line-height:1.21429em}div.output_stderr{background:#fdd}div.output_latex{text-align:left}div.output_javascript:empty{padding:0}.js-error{color:#8b0000}div.raw_input_container{font-family:monospace;padding-top:5px}span.raw_input_prompt{}input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}input.raw_input:focus{box-shadow:none}p.p-space{margin-bottom:10px}div.output_unrecognized{padding:5px;font-weight:700;color:red}div.output_unrecognized a,div.output_unrecognized a:hover{color:inherit;text-decoration:none}.rendered_html{color:#000}.rendered_html em{font-style:italic}.rendered_html strong{font-weight:700}.rendered_html :link,.rendered_html :visited,.rendered_html u{text-decoration:underline}.rendered_html h1{font-size:185.7%;margin:1.08em 0 0;font-weight:700;line-height:1}.rendered_html h2{font-size:157.1%;margin:1.27em 0 0;font-weight:700;line-height:1}.rendered_html h3{font-size:128.6%;margin:1.55em 0 0;font-weight:700;line-height:1}.rendered_html h4{font-size:100%;margin:2em 0 0;font-weight:700;line-height:1}.rendered_html h5,.rendered_html h6{font-size:100%;margin:2em 0 0;font-weight:700;line-height:1;font-style:italic}.rendered_html h1:first-child{margin-top:.538em}.rendered_html h2:first-child{margin-top:.636em}.rendered_html h3:first-child{margin-top:.777em}.rendered_html h4:first-child,.rendered_html h5:first-child,.rendered_html h6:first-child{margin-top:1em}.rendered_html ul{list-style:disc;margin:0 2em;padding-left:0}.rendered_html ul ul{list-style:square;margin:0 2em}.rendered_html ul ul ul{list-style:circle;margin:0 2em}.rendered_html ol{list-style:decimal;margin:0 2em;padding-left:0}.rendered_html ol ol{list-style:upper-alpha;margin:0 2em}.rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}.rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}.rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}.rendered_html *+ol,.rendered_html *+ul{margin-top:1em}.rendered_html hr{color:#000;background-color:#000}.rendered_html pre{margin:1em 2em}.rendered_html code,.rendered_html pre{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}.rendered_html blockquote{margin:1em 2em}.rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}.rendered_html td,.rendered_html th,.rendered_html tr{border:1px solid #000;border-collapse:collapse;margin:1em 2em}.rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}.rendered_html th{font-weight:700}.rendered_html *+table{margin-top:1em}.rendered_html p{text-align:left}.rendered_html *+p{margin-top:1em}.rendered_html img{display:block;margin-left:auto;margin-right:auto}.rendered_html *+img{margin-top:1em}.rendered_html img,.rendered_html svg{max-width:100%;height:auto}.rendered_html img.unconfined,.rendered_html svg.unconfined{max-width:none}div.text_cell{display:-webkit-box;-webkit-box-orient:horizontal;display:-moz-box;-moz-box-orient:horizontal;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}@media (max-width:540px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:0;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}.text_cell.rendered .input_area{display:none}.text_cell.rendered .rendered_html{overflow-x:auto}.text_cell.unrendered .text_cell_render{display:none}.cm-header-1,.cm-header-2,.cm-header-3,.cm-header-4,.cm-header-5,.cm-header-6{font-weight:700;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.cm-header-1{font-size:185.7%}.cm-header-2{font-size:157.1%}.cm-header-3{font-size:128.6%}.cm-header-4{font-size:110%}.cm-header-5,.cm-header-6{font-size:100%;font-style:italic}/*! +* +* IPython notebook webapp +* +*/@media (max-width:767px){.notebook_app{padding-left:0;padding-right:0}}#ipython-main-app{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;height:100%}div#notebook_panel{margin:0;padding:0;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;height:100%}#notebook{font-size:14px;line-height:20px;overflow-y:hidden;overflow-x:auto;width:100%;padding-top:20px;margin:0;outline:0;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;min-height:100%}@media not print{#notebook-container{padding:15px;background-color:#fff;min-height:0;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}}div.ui-widget-content{border:1px solid #ababab;outline:0}pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:2px;padding:.4em .4em .4em 2em}p.dialog{padding:.2em}code,kbd,pre,samp{white-space:pre-wrap}#fonttest{font-family:monospace}p{margin-bottom:0}.end_space{min-height:100px;transition:height .2s ease}.notebook_app #header{-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}@media not print{.notebook_app{background-color:#eee}}.celltoolbar{border:thin solid #CFCFCF;border-bottom:none;background:#EEE;border-radius:2px 2px 0 0;width:100%;height:29px;padding-right:4px;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end;font-size:87%;padding-top:3px}@media print{.edit_mode div.cell.selected{border-color:transparent}div.code_cell{page-break-inside:avoid}#notebook-container{width:100%}.celltoolbar{display:none}}.ctb_hideshow{display:none;vertical-align:bottom}.ctb_global_show .ctb_show.ctb_hideshow{display:block}.ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input,.ctb_global_show .ctb_show~div.text_cell_render{border-top-right-radius:0;border-top-left-radius:0}.ctb_global_show .ctb_show~div.text_cell_render{border:1px solid #cfcfcf}.celltoolbar select{color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;line-height:1.5;border-radius:1px;width:inherit;font-size:inherit;height:22px;padding:0;display:inline-block}.celltoolbar select:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.celltoolbar select::-moz-placeholder{color:#999;opacity:1}.celltoolbar select:-ms-input-placeholder{color:#999}.celltoolbar select::-webkit-input-placeholder{color:#999}.celltoolbar select[disabled],.celltoolbar select[readonly],fieldset[disabled] .celltoolbar select{background-color:#eee;opacity:1}.celltoolbar select[disabled],fieldset[disabled] .celltoolbar select{cursor:not-allowed}textarea.celltoolbar select{height:auto}select.celltoolbar select{height:30px;line-height:30px}select[multiple].celltoolbar select,textarea.celltoolbar select{height:auto}.celltoolbar label{margin-left:5px;margin-right:5px}.completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:2px;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;line-height:1}.completions select{background:#fff;outline:0;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000;width:auto}.completions select option.context{color:#286090}#kernel_logo_widget{float:right!important;float:right}#kernel_logo_widget .current_kernel_logo{display:none;margin-top:-1px;margin-bottom:-1px;width:32px;height:32px}#menubar{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;margin-top:1px}#menubar .navbar{border-top:1px;border-radius:0 0 2px 2px;margin-bottom:0}#menubar .navbar-toggle{float:left;padding-top:7px;padding-bottom:7px;border:none}#menubar .navbar-collapse{clear:left}.nav-wrapper{border-bottom:1px solid #e7e7e7}i.menu-icon{padding-top:4px}ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropdown-submenu>a:after{font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:block;content:"\f0da";float:right;color:#333;margin-top:2px;margin-right:-10px}.dropdown-submenu>a:after.pull-left{margin-right:.3em}.dropdown-submenu>a:after.pull-right{margin-left:.3em}.dropdown-submenu:hover>a:after{color:#262626}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px}#notification_area{float:right!important;float:right;z-index:10}.indicator_area{float:right!important;float:right;color:#777;margin-left:5px;margin-right:5px;z-index:10;text-align:center;width:auto}#kernel_indicator{float:right!important;float:right;color:#777;margin-left:5px;margin-right:5px;z-index:10;text-align:center;width:auto;border-left:1px solid}#kernel_indicator .kernel_indicator_name{padding-left:5px;padding-right:5px}#modal_indicator{float:right!important;float:right;color:#777;margin-left:5px;margin-right:5px;z-index:10;text-align:center;width:auto}#readonly-indicator{float:right!important;float:right;color:#777;z-index:10;text-align:center;width:auto;display:none;margin:2px 0 0}.modal_indicator:before{width:1.28571429em;text-align:center}.edit_mode .modal_indicator:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f040"}.edit_mode .modal_indicator:before.pull-left{margin-right:.3em}.edit_mode .modal_indicator:before.pull-right{margin-left:.3em}.command_mode .modal_indicator:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:' '}.command_mode .modal_indicator:before.pull-left{margin-right:.3em}.command_mode .modal_indicator:before.pull-right{margin-left:.3em}.kernel_idle_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f10c"}.kernel_idle_icon:before.pull-left{margin-right:.3em}.kernel_idle_icon:before.pull-right{margin-left:.3em}.kernel_busy_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f111"}.kernel_busy_icon:before.pull-left{margin-right:.3em}.kernel_busy_icon:before.pull-right{margin-left:.3em}.kernel_dead_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f1e2"}.kernel_dead_icon:before.pull-left{margin-right:.3em}.kernel_dead_icon:before.pull-right{margin-left:.3em}.kernel_disconnected_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f127"}.kernel_disconnected_icon:before.pull-left{margin-right:.3em}.kernel_disconnected_icon:before.pull-right{margin-left:.3em}.notification_widget{z-index:10;background:rgba(240,240,240,.5);margin-right:4px;color:#333;background-color:#fff;border-color:#ccc}.notification_widget.active,.notification_widget.focus,.notification_widget:active,.notification_widget:focus,.notification_widget:hover,.open>.dropdown-toggle.notification_widget{color:#333;background-color:#e6e6e6;border-color:#adadad}.notification_widget.active,.notification_widget:active,.open>.dropdown-toggle.notification_widget{background-image:none}.notification_widget.disabled,.notification_widget.disabled.active,.notification_widget.disabled.focus,.notification_widget.disabled:active,.notification_widget.disabled:focus,.notification_widget.disabled:hover,.notification_widget[disabled],.notification_widget[disabled].active,.notification_widget[disabled].focus,.notification_widget[disabled]:active,.notification_widget[disabled]:focus,.notification_widget[disabled]:hover,fieldset[disabled] .notification_widget,fieldset[disabled] .notification_widget.active,fieldset[disabled] .notification_widget.focus,fieldset[disabled] .notification_widget:active,fieldset[disabled] .notification_widget:focus,fieldset[disabled] .notification_widget:hover{background-color:#fff;border-color:#ccc}.notification_widget .badge{color:#fff;background-color:#333}.notification_widget.warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.notification_widget.warning.active,.notification_widget.warning.focus,.notification_widget.warning:active,.notification_widget.warning:focus,.notification_widget.warning:hover,.open>.dropdown-toggle.notification_widget.warning{color:#fff;background-color:#ec971f;border-color:#d58512}.notification_widget.warning.active,.notification_widget.warning:active,.open>.dropdown-toggle.notification_widget.warning{background-image:none}.notification_widget.warning.disabled,.notification_widget.warning.disabled.active,.notification_widget.warning.disabled.focus,.notification_widget.warning.disabled:active,.notification_widget.warning.disabled:focus,.notification_widget.warning.disabled:hover,.notification_widget.warning[disabled],.notification_widget.warning[disabled].active,.notification_widget.warning[disabled].focus,.notification_widget.warning[disabled]:active,.notification_widget.warning[disabled]:focus,.notification_widget.warning[disabled]:hover,fieldset[disabled] .notification_widget.warning,fieldset[disabled] .notification_widget.warning.active,fieldset[disabled] .notification_widget.warning.focus,fieldset[disabled] .notification_widget.warning:active,fieldset[disabled] .notification_widget.warning:focus,fieldset[disabled] .notification_widget.warning:hover{background-color:#f0ad4e;border-color:#eea236}.notification_widget.warning .badge{color:#f0ad4e;background-color:#fff}.notification_widget.success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.notification_widget.success.active,.notification_widget.success.focus,.notification_widget.success:active,.notification_widget.success:focus,.notification_widget.success:hover,.open>.dropdown-toggle.notification_widget.success{color:#fff;background-color:#449d44;border-color:#398439}.notification_widget.success.active,.notification_widget.success:active,.open>.dropdown-toggle.notification_widget.success{background-image:none}.notification_widget.success.disabled,.notification_widget.success.disabled.active,.notification_widget.success.disabled.focus,.notification_widget.success.disabled:active,.notification_widget.success.disabled:focus,.notification_widget.success.disabled:hover,.notification_widget.success[disabled],.notification_widget.success[disabled].active,.notification_widget.success[disabled].focus,.notification_widget.success[disabled]:active,.notification_widget.success[disabled]:focus,.notification_widget.success[disabled]:hover,fieldset[disabled] .notification_widget.success,fieldset[disabled] .notification_widget.success.active,fieldset[disabled] .notification_widget.success.focus,fieldset[disabled] .notification_widget.success:active,fieldset[disabled] .notification_widget.success:focus,fieldset[disabled] .notification_widget.success:hover{background-color:#5cb85c;border-color:#4cae4c}.notification_widget.success .badge{color:#5cb85c;background-color:#fff}.notification_widget.info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.notification_widget.info.active,.notification_widget.info.focus,.notification_widget.info:active,.notification_widget.info:focus,.notification_widget.info:hover,.open>.dropdown-toggle.notification_widget.info{color:#fff;background-color:#31b0d5;border-color:#269abc}.notification_widget.info.active,.notification_widget.info:active,.open>.dropdown-toggle.notification_widget.info{background-image:none}.notification_widget.info.disabled,.notification_widget.info.disabled.active,.notification_widget.info.disabled.focus,.notification_widget.info.disabled:active,.notification_widget.info.disabled:focus,.notification_widget.info.disabled:hover,.notification_widget.info[disabled],.notification_widget.info[disabled].active,.notification_widget.info[disabled].focus,.notification_widget.info[disabled]:active,.notification_widget.info[disabled]:focus,.notification_widget.info[disabled]:hover,fieldset[disabled] .notification_widget.info,fieldset[disabled] .notification_widget.info.active,fieldset[disabled] .notification_widget.info.focus,fieldset[disabled] .notification_widget.info:active,fieldset[disabled] .notification_widget.info:focus,fieldset[disabled] .notification_widget.info:hover{background-color:#5bc0de;border-color:#46b8da}.notification_widget.info .badge{color:#5bc0de;background-color:#fff}.notification_widget.danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.notification_widget.danger.active,.notification_widget.danger.focus,.notification_widget.danger:active,.notification_widget.danger:focus,.notification_widget.danger:hover,.open>.dropdown-toggle.notification_widget.danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.notification_widget.danger.active,.notification_widget.danger:active,.open>.dropdown-toggle.notification_widget.danger{background-image:none}.notification_widget.danger.disabled,.notification_widget.danger.disabled.active,.notification_widget.danger.disabled.focus,.notification_widget.danger.disabled:active,.notification_widget.danger.disabled:focus,.notification_widget.danger.disabled:hover,.notification_widget.danger[disabled],.notification_widget.danger[disabled].active,.notification_widget.danger[disabled].focus,.notification_widget.danger[disabled]:active,.notification_widget.danger[disabled]:focus,.notification_widget.danger[disabled]:hover,fieldset[disabled] .notification_widget.danger,fieldset[disabled] .notification_widget.danger.active,fieldset[disabled] .notification_widget.danger.focus,fieldset[disabled] .notification_widget.danger:active,fieldset[disabled] .notification_widget.danger:focus,fieldset[disabled] .notification_widget.danger:hover{background-color:#d9534f;border-color:#d43f3a}.notification_widget.danger .badge{color:#d9534f;background-color:#fff}div#pager{background-color:#fff;font-size:14px;line-height:20px;overflow:hidden;display:none;position:fixed;bottom:0;width:100%;max-height:50%;padding-top:8px;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2);z-index:100;top:auto!important}div#pager pre{line-height:1.21429em;color:#000;background-color:#f7f7f7;padding:.4em}div#pager #pager-button-area{position:absolute;top:8px;right:20px}div#pager #pager-contents{position:relative;overflow:auto;width:100%;height:100%}div#pager #pager-contents #pager-container{position:relative;padding:15px 0;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}div#pager .ui-resizable-handle{top:0;height:8px;background:#f7f7f7;border-top:1px solid #cfcfcf;border-bottom:1px solid #cfcfcf}div#pager .ui-resizable-handle::after{content:'';top:2px;left:50%;height:3px;width:30px;margin-left:-15px;position:absolute;border-top:1px solid #cfcfcf}.quickhelp{display:-webkit-box;-webkit-box-orient:horizontal;display:-moz-box;-moz-box-orient:horizontal;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.shortcut_key{display:inline-block;width:20ex;text-align:right;font-family:monospace}.shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}span.save_widget{margin-top:6px}span.save_widget span.filename{height:1em;line-height:1em;padding:3px;margin-left:16px;border:none;font-size:146.5%;border-radius:2px}span.save_widget span.filename:hover{background-color:#e6e6e6}span.autosave_status,span.checkpoint_status{font-size:small}@media (max-width:767px){span.save_widget{font-size:small}span.autosave_status,span.checkpoint_status{display:none}}@media (min-width:768px)and (max-width:991px){span.checkpoint_status{display:none}span.autosave_status{font-size:x-small}}.toolbar{padding:0;margin-left:-5px;margin-top:2px;margin-bottom:5px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}.toolbar label,.toolbar select{width:auto;vertical-align:middle;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:3px 0 0}.toolbar .btn{padding:2px 8px}.toolbar .btn-group{margin-top:0;margin-left:5px}#maintoolbar{margin-bottom:-3px;margin-top:-8px;border:0;min-height:27px;margin-left:0;padding-top:11px;padding-bottom:3px}#maintoolbar .navbar-text{float:none;vertical-align:middle;text-align:right;margin-left:5px;margin-right:0;margin-top:0}.select-xs{height:24px}@-moz-keyframes fadeOut{from{opacity:1}to{opacity:0}}@-webkit-keyframes fadeOut{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeIn{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}.bigtooltip{overflow:auto;height:200px;-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms}.smalltooltip{-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms;text-overflow:ellipsis;overflow:hidden;height:80px}.tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}.tooltiptext{padding-right:30px}.ipython_tooltip{max-width:700px;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:1px solid #ababab;outline:0;padding:3px 3px 3px 7px;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:2px;position:absolute;z-index:1000}.ipython_tooltip a{float:right}.ipython_tooltip .tooltiptext pre{border:0;border-radius:0;font-size:100%;background-color:#f7f7f7}.pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}.pretooltiparrow:before{background-color:#f7f7f7;border:1px solid #ababab;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}.terminal-app{background:#eee}.terminal-app #header{background:#fff;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}.terminal-app .terminal{float:left;font-family:monospace;color:#fff;background:#000;padding:.4em;border-radius:2px;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.4);box-shadow:0 0 12px 1px rgba(87,87,87,.4)}.terminal-app .terminal,.terminal-app .terminal dummy-screen{line-height:1em;font-size:14px}.terminal-app .terminal-cursor{color:#000;background:#fff}.terminal-app #terminado-container{margin-top:20px} +/*# sourceMappingURL=style.min.css.map */ + </style> +<style type="text/css"> + .highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #408080; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #BC7A00 } /* Comment.Preproc */ +.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #7D9029 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #A0A000 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ + </style> + + +<style type="text/css"> +/* Overrides of notebook CSS for static HTML export */ +body { + overflow: visible; + padding: 8px; +} + +div#notebook { + overflow: visible; + border-top: none; +} + +@media print { + div.cell { + display: block; + page-break-inside: avoid; + } + div.output_wrapper { + display: block; + page-break-inside: avoid; + } + div.output { + display: block; + page-break-inside: avoid; + } +} +</style> + +<!-- Custom stylesheet, it must be in the same directory as the html file --> +<link rel="stylesheet" href="custom.css"> + +<!-- Loading mathjax macro --> +<!-- Load mathjax --> + <script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script> + <!-- MathJax configuration --> + <script type="text/x-mathjax-config"> + MathJax.Hub.Config({ + tex2jax: { + inlineMath: [ ['$','$'], ["\\(","\\)"] ], + displayMath: [ ['$$','$$'], ["\\[","\\]"] ], + processEscapes: true, + processEnvironments: true + }, + // Center justify equations in code and markdown cells. Elsewhere + // we use CSS to left justify single line equations in code cells. + displayAlign: 'center', + "HTML-CSS": { + styles: {'.MathJax_Display': {"margin": 0}}, + linebreaks: { automatic: true } + } + }); + </script> + <!-- End of mathjax configuration --></head> +<body> + <div tabindex="-1" id="notebook" class="border-box-sizing"> + <div class="container" id="notebook-container"> + +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<h1 id="Multimodal-(Gaussian-Mixture/Hidden-Markov)-Models-for-Motion-Sound-Mapping-—-Quickstart-guide">Multimodal (Gaussian Mixture/Hidden Markov) Models for Motion-Sound Mapping — Quickstart guide<a class="anchor-link" href="#Multimodal-(Gaussian-Mixture/Hidden-Markov)-Models-for-Motion-Sound-Mapping-—-Quickstart-guide">¶</a></h1><h2 id="Building-and-using-the-XMM-Python-library">Building and using the XMM Python library<a class="anchor-link" href="#Building-and-using-the-XMM-Python-library">¶</a></h2><p>See <a href="http://ircam-rnd.github.io/xmm/">http://ircam-rnd.github.io/xmm/</a></p> +<p>The python library reflects the sructure of the C++ library. The same classes and methods can be used on both implementations. +First, import the python library (needs to be within your Python search path).</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [1]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="kn">import</span> <span class="nn">xmm</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<h2 id="Using-GMMs-for-classification">Using GMMs for classification<a class="anchor-link" href="#Using-GMMs-for-classification">¶</a></h2><p>In this example, we illustrate the process of training and classification with Gaussian Mixture Models. We have 3 data files called "gmm_test_data1.txt", "gmm_test_data2.txt", "gmm_test_data3.txt". Each file contains a 2D array where each row is a data frame with 6 dimensions. The data was generated with the example patch from the Max/Mubu implementation (see <a href="http://julesfrancoise.com/mubu-probabilistic-models/">http://julesfrancoise.com/mubu-probabilistic-models/</a>)</p> +<h3 id="Building-a-training-set">Building a training set<a class="anchor-link" href="#Building-a-training-set">¶</a></h3><p>First, we need to record and annotate the training data. This is done using the <code>TrainingSet</code> class:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [2]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="o">%</span><span class="k">matplotlib</span> inline +<span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="kn">as</span> <span class="nn">plt</span> + +<span class="c1"># Create the training set</span> +<span class="n">training_set</span> <span class="o">=</span> <span class="n">xmm</span><span class="o">.</span><span class="n">TrainingSet</span><span class="p">()</span> +<span class="n">training_set</span><span class="o">.</span><span class="n">dimension</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span> <span class="c1"># dimension of data in this example</span> +<span class="n">training_set</span><span class="o">.</span><span class="n">column_names</span><span class="o">.</span><span class="n">set</span><span class="p">([</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">,</span> <span class="s1">'c'</span><span class="p">,</span> <span class="s1">'d'</span><span class="p">,</span> <span class="s1">'e'</span><span class="p">,</span> <span class="s1">'f'</span><span class="p">])</span> +<span class="c1"># Record data phrases</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span> + <span class="n">phrase</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/gmm_training_data{}.txt'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> + <span class="n">training_set</span><span class="o">.</span><span class="n">addPhrase</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> + <span class="k">for</span> <span class="n">frame</span> <span class="ow">in</span> <span class="n">phrase</span><span class="p">:</span> + <span class="c1"># Append data frame to the phrase i</span> + <span class="n">training_set</span><span class="o">.</span><span class="n">getPhrase</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">record</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>For most objects of the library, calling the <code>print</code> function from python will print the JSON file description of the current object. In this case, we can have a look at the data contained in the training set:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [3]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="k">print</span> <span class="s2">"Number of phrases in the training set: "</span><span class="p">,</span> <span class="n">training_set</span><span class="o">.</span><span class="n">size</span><span class="p">()</span> +<span class="k">print</span> <span class="s2">"Labels: "</span><span class="p">,</span> <span class="n">training_set</span><span class="o">.</span><span class="n">labels</span><span class="p">()</span> +<span class="k">print</span> <span class="s2">"names of the columns of the training data:"</span><span class="p">,</span> <span class="n">training_set</span><span class="o">.</span><span class="n">column_names</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> +</pre></div> + +</div> +</div> +</div> + +<div class="output_wrapper"> +<div class="output"> + + +<div class="output_area"><div class="prompt"></div> +<div class="output_subarea output_stream output_stdout output_text"> +<pre>Number of phrases in the training set: 3 +Labels: ('1', '2', '3') +names of the columns of the training data: ('a', 'b', 'c', 'd', 'e', 'f') +</pre> +</div> +</div> + +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>The training Set has 3 classes with integer labels 1, 2 and 3.</p> +<h3 id="Training-the-models">Training the models<a class="anchor-link" href="#Training-the-models">¶</a></h3><p>We can now train a <code>GMM</code> — i.e. a group of Gaussian Mixture Models with different class labels. +We start by creating an instance of the <code>GMM</code>, and we can then adjust the model parameters (number of Gaussians and regularization of the covariances) and train the models for all classes of the training set:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [4]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># Create a GMM (handles multiples labels for recognition)</span> +<span class="n">gmm</span> <span class="o">=</span> <span class="n">xmm</span><span class="o">.</span><span class="n">GMM</span><span class="p">()</span> +<span class="c1"># Set parameters</span> +<span class="n">gmm</span><span class="o">.</span><span class="n">configuration</span><span class="o">.</span><span class="n">gaussians</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> +<span class="n">gmm</span><span class="o">.</span><span class="n">configuration</span><span class="o">.</span><span class="n">relative_regularization</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mf">0.01</span><span class="p">)</span> +<span class="n">gmm</span><span class="o">.</span><span class="n">configuration</span><span class="o">.</span><span class="n">absolute_regularization</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mf">0.0001</span><span class="p">)</span> +<span class="c1"># Train all models</span> +<span class="n">gmm</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="n">training_set</span><span class="p">)</span> +<span class="k">print</span> <span class="s2">"number of models: "</span><span class="p">,</span> <span class="n">gmm</span><span class="o">.</span><span class="n">size</span><span class="p">()</span> +</pre></div> + +</div> +</div> +</div> + +<div class="output_wrapper"> +<div class="output"> + + +<div class="output_area"><div class="prompt"></div> +<div class="output_subarea output_stream output_stdout output_text"> +<pre>number of models: 3 +</pre> +</div> +</div> + +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<h3 id="Performing-Recognition">Performing Recognition<a class="anchor-link" href="#Performing-Recognition">¶</a></h3><p>The trained ModelGroup can be used directly to perform continuous recognition or classification with class-conditional GMMs.</p> +<p>We start by loading test data originatin from the same 3 distributions used for training:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [5]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># read test data (concatenation of 3 test examples labeled 1, 2, 3)</span> +<span class="n">test_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/gmm_test_data1.txt'</span><span class="p">)</span> +<span class="n">test_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">test_data</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/gmm_test_data2.txt'</span><span class="p">)))</span> +<span class="n">test_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">test_data</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/gmm_test_data3.txt'</span><span class="p">)))</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>Then, we can set additional attributes of the models, such as the size of the window used to smooth the likelihoods, and initialize the "performance mode". +We create several arrays that will store the normalized likelihoods and log-likelihoods during continuous recognition, and we can then perform the recognition continuously and causally by updating the recognition with each new frame of the test examples:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [6]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># Set Size of the likelihood Window (samples)</span> +<span class="n">gmm</span><span class="o">.</span><span class="n">shared_parameters</span><span class="o">.</span><span class="n">likelihood_window</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span> +<span class="c1"># Initialize performance phase</span> +<span class="n">gmm</span><span class="o">.</span><span class="n">reset</span><span class="p">()</span> +<span class="c1"># Create likelihood arrays for recognition</span> +<span class="n">instantaneous_likelihoods</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">gmm</span><span class="o">.</span><span class="n">size</span><span class="p">()))</span> +<span class="n">normalized_likelihoods</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">gmm</span><span class="o">.</span><span class="n">size</span><span class="p">()))</span> +<span class="n">log_likelihoods</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">gmm</span><span class="o">.</span><span class="n">size</span><span class="p">()))</span> +<span class="c1"># Performance: Play test data and record the likelihoods of the modes</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span> + <span class="n">gmm</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">xmm</span><span class="o">.</span><span class="n">vectorf</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]))</span> + <span class="n">instantaneous_likelihoods</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">gmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">instant_likelihoods</span><span class="p">)</span> + <span class="n">normalized_likelihoods</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">gmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">smoothed_normalized_likelihoods</span><span class="p">)</span> + <span class="n">log_likelihoods</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">gmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">smoothed_log_likelihoods</span><span class="p">)</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>We can finally plotthe normalized and log-likelihoods over time:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [7]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># Plot the likelihoods over time for the test phase</span> +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">311</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">instantaneous_likelihoods</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Instantaneous Likelihood of Each Model Over time"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Likelihood"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">((</span><span class="s2">"model 1"</span><span class="p">,</span> <span class="s2">"model 2"</span><span class="p">,</span> <span class="s2">"model 3"</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">312</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">normalized_likelihoods</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Normalized Smoothed Likelihood of Each Model Over time"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Normalized Likelihood"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">((</span><span class="s2">"model 1"</span><span class="p">,</span> <span class="s2">"model 2"</span><span class="p">,</span> <span class="s2">"model 3"</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">313</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">log_likelihoods</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Smoothed Log-Likelihood of Each Model Over time"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Log-Likelihood"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">((</span><span class="s2">"model 1"</span><span class="p">,</span> <span class="s2">"model 2"</span><span class="p">,</span> <span class="s2">"model 3"</span><span class="p">))</span> +</pre></div> + +</div> +</div> +</div> + +<div class="output_wrapper"> +<div class="output"> + + +<div class="output_area"><div class="prompt output_prompt">Out[7]:</div> + + +<div class="output_text output_subarea output_execute_result"> +<pre><matplotlib.legend.Legend at 0x112741dd0></pre> +</div> + +</div> + +<div class="output_area"><div class="prompt"></div> + + +<div class="output_png output_subarea "> +<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZUAAAEZCAYAAABfKbiYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz +AAALEgAACxIB0t1+/AAAIABJREFUeJzsnXecVcX5/9+fXZYqi3RB6YqJKFasEJF8xWD9GUsERYPY +voklJiRfO2qi0QQTRGOMqARrrIkgxmhAVCSoEUQsgKggRZSOggtbnt8fM3c5e7l397J7C3d33q/X +2b3nTHtmzpzzTDvPyMwIBAKBQCAdFORagEAgEAjUH4JSCQQCgUDaCEolEAgEAmkjKJVAIBAIpI2g +VAKBQCCQNoJSCQQCgUDaCEolsNMi6WpJ9/nf3SRVSNrhOivpFUnn+9/DJL0YcauQ1DN9UieVYYKk +m2sZ9lRJn0vaKGn/dMuWJM3Rkh7ORlrVyHC0pKUp+s25vDuKpBckDc+1HOkmKJVqkPSZpEF1jOM8 +Sa+nUabRkh5KV3y5pjplYWa/NbOLopfqmp6ZPWZmP0hnnFng98BPzKzYzObGO/ry+9orndj/UWlI +N+Wy8TKsjN5HSY0kfSWpPBsyVOdXUitJf5b0haRvJM2V9OM6yLVDJHpuzex4M8srRZgKjXItQANA +5MeLK5fksnyUw7RTpRvwYTXuBvQ1s8+yJE8y1gFDgCn+fAiwFmibM4kASUXAVGAlcBiwHPgfYKKk +Xc1sbJrTKzSzuijSvCb0VFIk1uOQ9HtJayV9IukHEfcf+2sb/f+hkr4D/Bk4wrcg13q/x0uaLWmD +pCWSRkfiibXcz/VuX0m6xrsdB1wD/MjHNyeS9oc+7UWSLorEd7SkpZJ+LulLScujLTRJjSWN8Wl9 +IekeSU0i7hdK+ljSakn/kNQpTs5oyzQ6zNRL0nRJ630eHq9FmScd0pB0mqRPJe3jzw+X9IakdZLm +SDo6SbhEPcdjJS309/XuiF9Juk7SYt8K/6uk4oj7yZLe9+Gm+fsdcztQ0jv+Hv8NaFpNPhOl09Lf +m69xz+l7kj5OFgVJlKOkfpJm+nJZLukuSY0i7n0kvSRpjb//V0WCN5E00dereZIOSpYHz8PAeZHz +c4GJcfJ0kvScT2+hpAsibk193tdKeh/olyDs074+fSLpshrkicqxB3C6mX1uZuVm9i/gcuBmSbtI ++pWkp+LSu1PSWP+7WNL9klb45+nXkuTdzpM0Q9IfJK0GRsfFk+y5jT4v0TjW+WfuSLln+3NfL86N +xFntc5tTzKzeHsADwJfAe7UM/xkwyP8+D6gANgGTgEuA5d5tCFAOzAcmALsB342Eey0u3u8Bffzv +fYEvgJP9eTefzl+AxkBfoATY27uPBh6Ki28I0N3/HuBlPMCfHw2U+nCF3u8moJV3/yPwD6AV0AJ4 +DrjFuw0CVgH7A0XAOODViJzlQEFEjleA8/3vx4Cr/e/GwJFJyni7eCJulXmN+gNGAAuBHt6tM7Aa +OM6ff9+ft00gV5X74ct6EtAS6AJ8BQz2buf7dLoBzYFnIvL0Br7xZVQI/BL4GNf7LwIW415ahcBp +wFbg5iRlkDSdiIw9qqmnFUDPJG4HAYfilE5X4APgcu+2C7AC+Jm/Ry2AfpGy3wwc58PeCvynGhnK +gX1wvYFiYFdcvd4HKI/4ew24y5fR/r68B3q324BXcXVxd2Ae8Ll3E/Bf4Fpfpt2BRcCxyZ6LSJqP +AxMSXC/EPRvH+rL5Bmjh3Qp82cTK4+/APbjGQTtgFnBhpE6VAj/x4ZpUV5eTPC/n+Tpyrs/rr4Gl +kbI6FtgINK/puc31kXMBMpo56A8cQPqUylLgBNxLqJl/mDv46+uBU4HfxCpKJNxrNaTzR+AO/zv2 +8uwUcX8TODNZ5UwQ39+By/zvo3FKJPry/xI41P/+hsgLCzgC+NT/vh+4LeLWwlf8rtSsVCYC9wK7 +1yDrjiiVCuAXwPtx5fMrYGJc2BeB4QnkSqRUjoicPwH8yv/+N3BJxK03sAX34rgO+FvETb4efA+n +2JfFyfMGyZVKonS2xsqEapRGxH09bqhpnf9/bBK/VwDP+N9nAe8k8TcaeCly/l1gUzUylAM9gfuA +i4CLcQ2jXnilglPapfgXo792K/Cg//1JVG7gQrYplcOAxXFpXgU8UNNzAbwM3JrE7QtgqP/9OnCO +/30s8LH/3RHXsGsSCXcWMC1SpxYnij9RXU7yvJwHLIi47evLtF3k2mrcMCdU89zm+qjXcypmNkNS +t+g1uZU+f8K1NjbjWhsLU4zyM9zNxMy+9b3fLrgKdz6utXo48K2kN8xsQaJIJB2Ka5Xti2shNgae +ivP2ZeT3ZlyrMiGShgA34F5GBTiF917Eyxozq4iPT1J7XMv4HZ8XfPjYSWfgnZiDmW2StAbXilyR +TB7PL3EK9i25Yb8/mNmEGsKkwijcy/mLyLVuwJmSTvLnwvUYpqYYZ7Ky7gwsibgt8fF2jHczM5O0 +DFc2Fbhxe+LCJqO6dL5IGGJ7DrQEcyqS9gL+AByCqxeN2HZPu+Be5MlYGfm9GWgqqSCuLlUm5f8/ +DPzW//6/OD+dgLVmtjlybQlwsP/dGVgW5xajK7C7r0ux9ApwPZ+aWO3TriqwVIh7D6z2lx4DhgKP ++P+PRdIuAr6IjXj54/NIdCmtUquBaD38FsDMVsddS+W5zSkNcU7lPuBSM+uHe/H9uY7xrcM9qGvM +bDCuhS6fDiSehH4M13Xd3cx2xbXoUq0QVeKT1Bh4Gvgd0N7MWgP/TDG+1biXRR8za+OPXc2slXdf +gXthx9JqgZt0XYbr/YCr3DF2qxTS7Cszu8jMdscNFd6jui/dNWAwcL2kH0auL8W1AmN5aG1mLc3s +93VMr0r+/e8y3MMf7wbuJb0cpwj2iHPruoPplFL1JVMTye73n4GPgF6+rl0b8bsU15NIG2b2Ou4F +3sHM3ohzXgG08fUoRle2KeAvcGUYI1omS3Et8eg9bmVmJ1Ez/waGSGoWd/10XINwlj9/ChgoaXfc +qENMqSz1/tpG0t7VzPpGs16DDDW57wg1Pbc5pUEpFV+ZjwSe8pNlf8G1BmPfAsyT9F7swLU6f5s8 +xkr+F3hI0ls4JVOOa62CezHsIbcCJcYuwDozK/W9lmHxolaT1pdAd21rosR6OqvNrML3WganIDPm ++s3jgbG+9YOk3SXFwj8OjJDU108C3grMMrOlvgW1HDhHUoGfcKx8QUk63T+c4IZmKiJlEo9wreAm +kSNRGQg3J/AD4O5Iz+QR4CRJg70sTeUWKHROpRyq4XHgSkndJe0C3IIb8qoAngROkHSM3NLZUbgX +z0zgP0CppMu82w9x8xq1SaeutAQ2mtlmuYUE/xtxex7YTdLlfuJ3F18fk5Fqw+dE4JT4cGa2DFc+ +v/X3uC8wEte7AVemV0vaVdIewKWRON4CvvYT6k0lFcotMjgkBXkexjWEnpJbYNLIT57fCYw2s6+9 +fKtxczoTcApsgb++EngJ+KPcAgpJ6inpeymWB2z/3KZCQr8pPLc5pUEpFVx+15nZQWZ2oD/2BTCz +v5vZfmbWN3bgKuLV1cQXa328i2s97IWb9Cxg28M7DfciXCnpK3/tp8CvJW3Ajc0/kSTeROdP4Srb +Gkn/NbNvcOPkT/mhgbNwk3bVEY3vKtyE5yxJ63EPT28AM5sKXA88i1MgPXz8MS7EzWesxo25R1um +/YA3JW3E9couN7PF1cjzNa719a3/f0wyuc3sPeAk4D5Jx/mX1Sm4FTarcMMmo9hWv6trJVZX1g/i +Xkiv4YaJNuMm3/FDpucAd/s0TwBOMrMyMysFfohbULAGOAM3+Z6MpOmkIH/Mfa6qfqfyB+82Cjjb +34e/AH+rDOTqzrHAybihroXAwBrSqdHNzD4ys4+ShBuKq0crcGVyvZm94t1uwg0pfYabE6v8rsMr +2BNxc6Sf4Sb4x+MWBVSLmW3FLSFeipuf3ACMwS0k+UOc98dwCz0ejbt+Lq7x9iFuzuopIj3zFKjy +3MZEq0n0as6TPre5Rn6SJ6+Q1Ao3ibwvrvV7vpm9mcRvd2Cyme3nz2cAY83saX/e17+kUk17IPCL +aLdbUnszW+Vb81OA35jZ9FpkLRAIBPKafO2p3Am8YGbfxS1L/CiRJ0mP4brbveXWeo8AzgZGSnpX +bi38yakmKuk1XK9ikI/vWO/0S0kf4noszwWFEggEGip511OR+/hsjpmldYIxEAgEAnUnH3sqPYDV +cgb6Zku6L8GqjkAgEAjkgHxUKo1wXwn/ycwOwk1qXlV9kEAgEAhkg3z8+HEZsNTMYisonmb7j6yQ +lF/jeoFAILCTYGa1/pAy73oqZvYlsFRSbPnc90liwTUbJglydYwePTrnMoS8hfyF/NW/o67kY08F +3Br+R/0HhZ/ivgcIBAKBQI7JS6VibqOifjV6DAQCgUBWybvhr4bI2rUwb17VawMHDsyJLNmgPucN +Qv7ynfqev7qSd9+ppIokqy95O+MMePppqCfZCQQCOzGSsDpM1Ofl8JekxTj7PRVAqZlVZwQv79m0 +qWY/gUA+0717d5YsqW53gEC66datG4sXL057vHmpVHDKZKCZrcu1INmgIh22agOBnZglS5akZeVR +IHV2zGBy6uTrnEpsg54GQVAqgUAgX8jXF7MBL0t6W9KFuRYm05SX51qCQCAQSI2sD39Jmkc1+whY +1d3UknGUmX3hN6h5WdJHZjYjbULuZISeSiAQyBdyMadyov//U/8/tuvb2alGYH5/cnN7mPwdt6ve +dkrlxhtvrPw9cODAvF0KGJRKIFB/GTFiBF26dOHmm2+u0W+PHj144IEHGDRoUNrSnz59OtOnT09b +fFlXKma2BEDSsWZ2YMTpKkmzqcE4pKTmQIGZfeO3Bx6M2zFuO6JKJZ8JSiUQCNTE9OnTufnmm5k9 +ezZt2rTh008/TSlcfIP7ppsSvk5TJpdzKpJ0VOTkyBTl6QjM8HvMz8Lt6vhShmTcKQhKJRAI1ESL +Fi0YOXIkY8aMyakcuVQqI4F7JC2WtAS4Bzi/pkBm9pmZHWBuf/n9zOy2jEuaY8JEfSCQW3r06MGY +MWPo27cvxcXFXHDBBXz11Vccf/zxtGrVisGDB7Nhw4ZK/5MmTWLfffelTZs2DBo0iPnz51e6zZkz +h4MPPphWrVpx1llnUVJSUiWt559/ngMPPJDWrVvTv39/5sWb00hCv379OPvss+nRo0d6Ml1LcqZU +zOwdM9sftx1wX68oZudKnp2Z0FMJBHLPs88+y7Rp01iwYAGTJ09myJAh3HbbbaxatYry8nLGjRsH +wMKFCxk2bBjjxo1j1apVDBkyhJNOOomysjJKS0s59dRTOe+881i7di1nnHEGzzzzTGUac+bMYeTI +kYwfP561a9dy8cUXc/LJJ1NaWpqrbO8wOVMqklpJ+gMwFZgq6Q5JrXIlz85MUCqBAEjpOWrLZZdd +Rrt27ejUqRMDBgzg8MMPp2/fvjRu3JhTTz2VOXPmAPDkk09y4oknMmjQIAoLCxk1ahQlJSXMnDmT +WbNmUVZWxuWXX05hYSGnnXYa/fpts407fvx4LrnkEg455BAkMXz4cJo0acKsWbPqWnxZI5fDXw8C +XwNn+mMjMCHVwJIK/HbCkzIk305DUCqBgLN9l46jtnTs2LHyd7NmzbY7/+abbwBYsWIF3bp1q3ST +xB577MHy5ctZsWIFu+++e5V4o36XLFnCHXfcQZs2bWjTpg2tW7dm2bJlrFixovaCZ5lcmmnpZWan +Rc5vkvTuDoS/Arc5V3F6xdr5CEolEMgfOnfuzPvvv1/l2tKlSyuVybJly6q4ff755+y5554AdOnS +hWuvvZarr746O8JmgFz2VL6V1D924leCfZtKQEl7AMcD92dItp2KoFQCgfzhzDPPZMqUKbzyyiuU +lZUxZswYmjZtypFHHskRRxxBUVERd911F2VlZTz77LO89dZblWEvvPBC7r333sprmzZt4oUXXmBT +ClZlzYwtW7awdetWKioq2LJlS07mYnKpVP4X+FNk9dfdwMUphv0j8Euq+TK/PhFWfwUCuSXe+GJ1 +xhh79+7NI488wqWXXkr79u2ZMmUKkydPplGjRhQVFfHss88yYcIE2rZty1NPPcVpp20bsDn44IMZ +P348l156KW3atKF3795MnDgxpXRfe+01mjVrxoknnsjSpUtp3rw5xx13XB1yXTtyvp+KpGIAM9uY +ov8TgCFmdqmkgcAvzOykBP5s9OjRlef5/EX9d78L8+eH/VQC9Re/h0euxWhQxMo8/ov6m266qU77 +qeRMqfiVXqOB7/lLrwI3m9mG5KFA0q3AOUAZ0AxoCTxrZufG+as3m3TtvTcsXBiUSqD+EpRK9klW +5nXdpCvvVn+Z2TVm1tXMegJnAdPiFUp9I8ypBAKBfCGfV381GIJSCQQC+UJerv6KYWavmtnJaZds +JyMolUAgkC/ksqdyCfCQn1sRsBb4cQ7l2WkJSiUQCOQLOVMqZjYX2H9HV381RIJSCQQC+ULOlIqk +JsBpQHegUWz9tZlVu1OND/ca0Ngfz5nZNRkVNscEpRIIBPKFXA5/PQdsAN4BtqQayMy2SDrGzDZL +KgTekHSUmb2RKUFzTVAqgUAgX8ilUtnDzH5Qm4Bmttn/bIJbbLAubVLtZLz3HqxcmWspAoFApsj1 +dsLpJperv2ZK2q82Ab2F4jnASmC6mX2YXtF2Hs48M9cSBAKBfGDMmDHst99+FBcX06tXr5ztAJn1 +noqkeTibXY2AEZI+xQ1/CTAz61tTHGZWARzoJ/lfknS0mb0a7y+6R32+mmnp0wcWLMi1FIFAIB94 ++OGH6du3L4sWLWLw4MF07dqVM2tomcabaakzZpbVA+hW3VGL+K7H2f+Kv271gV/9attOEIFAfWVn +f167d+9uv//9722//fazli1b2siRI+3LL7+0IUOGWHFxsR177LG2fv36Sv/PPfec9enTx1q3bm3H +HHOMffTRR5Vus2fPtoMOOsiKi4vtRz/6kZ111ll2/fXXV7pPnjzZDjjgANt1113tqKOOsvfee6+K +HFOnTk1J5ssvv9wuv/zypO7Jytxfr/U7PhfDX+vMbAnOREuio1oktYvtECmpGXAsUK+/xD/pJCgq +yrUUgUDDJt+2E3799dfp06dP2vKfKrmYqH8MOBG36stww14xDOhZQ/hOwES5NcgFwMNmNjUTgu4M +lJZC//4wZUquJQkEcotuqsNewBFsdO0MV8a2EwYYMGAAHTt2pG9fN1p/6qmnMm3aNKDqdsIAo0aN +Yty4ccycORNJldsJA9VuJwwwfPhwbrnlFmbNmsWAAQNSlnX06NGYGSNGjKhVXutC1pWKmZ3o//eo +Zfh5wEFpFWonprQUmjRxy4rN6rbHdiCQz9RWGaSLdGwnXFBQUON2wg899BB33XUX4KYnSktLd2g7 +4bvvvptHHnmEGTNmUJSDIY5cTNRXqxDMbHa2ZMkHSkuhcWOnTIJSCQR2fnK5nfCDDz7I7373O15/ +/XU6depUqzjqSi7mVO6o5sjNGridmNJSN59SUBB2gAwE8oFcbSf86KOPcu211/Lyyy9X6f1km6wr +FTM7ppqjxi96JO0haZqkDyTNk3R5NuTOFTGlUlgYlEogkCvyYTvh66+/nrVr19KvXz9atmxJcXEx +P/nJT+qQ69qRy50fmwM/B7qa2UWS9gL2NrPnawi3G7Cbmb0raRfchP8pZjY/zp/lKm/pZNgwOPFE +uOACWLUKWrTItUSBQPoJOz9mn/q48+MEYCtwpD9fDvympkBmttLM3vW/vwE+AnavPlT+EnoqgUAg +n8ilUullZr8DSqHSntcOaUdJ3YEDgDfTLdzOQlAqgUAgn8ilQcmt/uNFA5DUix2wVuyHvp4GrvA9 +lu2oD2ZaSkuhUSM3UR+sFQcCgXSTbjMtuZxTORa4DtgHeAk4CvixmU1PIWwj4Hngn2Z2ZxI/9WJO +ZfBg+MUv4Jxz4IMPoEOHXEsUCKSfMKeSfTI1p5LLnR9fljQbOBw37HWFma1OMfiDwIfJFEp9Igx/ +BQKBfCJncyqSbjazNWY2xa/4Wivp0RTCHQWcDQySNEfSbEm12pclHwhKJRAI5BO5nFPpIulqM/ut +3yL4SWBOTYHM7fBYmHHpdhKCUgkEAvlELld/nQ/sJ+lqYDJus60bcyjPTklZWVAqgUAgf8i6UpF0 +kLf/dSBwJ/Aj4GPg1ZrsgjVEomZawuqvQKD+MWLECG644YaU/Pbo0aPSGvLOSq5tf92G219+H1K0 +/SXpAUlfSnovo1LuJIThr0AgkApjx46lV69eFBcXs9tuu3H++edXWk7OJnln+wv3Jf5xmZZzZyEo +lUAgkAqnnHIK//3vf9m4cSPz589nyZIl3HLLLVmXIxfDX+f4/z9PdNQU3sxm4Ho3DYKgVAKB3NOj +Rw/GjBlD3759KS4u5oILLuCrr77i+OOPp1WrVgwePJgNGzZU+p80aRL77rsvbdq0YdCgQcyfv800 +4Zw5czj44INp1aoVZ511FiUlJVXSev755znwwANp3bo1/fv3Z968eSnL2Lp1awDKy8spKCjIifn7 +XAx/xUwitkxw7JIDeXZqYl/UB6USCOSWfNhO+PHHH6dVq1Z06NCBDh06VO4wmU1ysfPjX/z/m+Ld +JP0snWnVFzMtsZ5KmKgPNGjStUNdLb/cz4fthIcOHcrQoUP55JNPOP300xk7diw/+1n1r9V0m2nJ +5Xcqifg5MDZdkUWVSr4SXVJcVpZraQKBHJJjMy75sp0wQK9evbjqqqu4/fbba1Qq8Q3um27arr2/ +Q+xsSiXVpoh2wG9eE+upFBdDZMg2EAjspORyO+EopaWlNG/evM7x7Ci5/PgxETU2RSQ9BswEekv6 +XNKIzIuVO2JKpV07WLMm19IEAoGayNV2wg888ACrVq0C4MMPP+S2226rsqtktkhbT0XSZKpRCmZ2 +svf3dRJ/AprVlI6ZDautjPlITKm0bQurUzW3GQgE0kpttxNesWIFBxxwQOV2wuAm/C+44AKuu+46 +jj/++KTbCS9atIhmzZrRv39/jj766BrTfeONN7j22mvZvHkznTt3ZuTIkVx55ZV1yXatSJvpe0lH ++58/BHYDHvHnQ4EvzSyruasPpu/Ly6FxY/f/hhvcvMro0bmWKhBIP8H0ffbZ6U3fm9mrXqA7zOyQ +iNNkSf9NVzoNifXr3VwKuJ7KJ5/kVp5AIBCoiUzMqbSQ1DN2IqkH275NSQuSfiBpvqSFkv4vnXHv +THz6KfT0JRk//JXOJYA7G/U5bxDyF6jfZEKpXAlMlzRd0qvAK8AV6YpcUgFwN85USx9gqKTvpCv+ +nYmoUmnXLiiV+kLIX6A+k/YlxWb2oqS9gNiLfr6Zpbz3fAocCnxsZksAJP0NOAWYX22oPCSqVPbZ +B2bPhpISaNo0t3IFAoFAMtKuVCQVARcD3/OXpkv6i5mlZmegZnYHlkbOl+EUzXbk2kL0Qw/dxPLl +i7j66of56quljBzZh0mTNlS7giNGWRk88QTElqt37QqHHurOTzgBPvsMXnkFhg3rwahRD3DQQanY +4tw5WLlyCWef3YOXXy6joGD7znIsb6lS2zI44YSWPPDAPHbbrTu33z6CDh26MGLEzTsUx9y5r3Lr +refwxBOuSp5//r5cccU97L//95g40d3/a655uEqYHc1fTdRUntWxdWsJN954BvPmvU6/fsdxww1P +1FmeVPL3/e8X8PDDi+jcuWf1HjPIMcccw/Dhwzn//PNr9FtQUMCiRYvo2TN38u4IM2bM4MILL+Sj +jz6q1l/8ffKfy9QNM0vrAdwPTAQG+WMCcH8a4z8NuM//XgxsAP4UcR+JG3KzcIQjHPlzJGP06NEm +ycaNG1fl+tixY02S3XTTTUnDVsfAgQPtgQceSMlvQUGBffLJJ0ndJ0+ebIceeqi1aNHC2rVrZ+ec +c44tW7asVnLVBknVypeIGu5F7d/RdQmcMEKYm8q1OsR/OPCi//0Z8A3wz4j7SGBaLeNWmstiNPBQ +uss4Lo3PgEFJ3Kbh9qlpips/2x84LpPypCIj0A0oBwqyUAYTgJtTiCMlfwnCHQ18nqv7X9fyBK6t +TsZM5QGoAHrGzps2bboy10qtoR1NmzZdmYn6mImJ+nJJvWInfiVYOu3rvg3sKambP98IHC6pOJFn +SUdKekvSOklvSjoi4vaKpN9ImiFpE9DDX/u1pDckfS3pOUltJT0iaYOPo2skjrH+y/4Nkt6W1D+J +HN0kVUgqkHS4j3ujP76V9Kn3J0lXSVokaZWkv0naNRLPcEmLvds1NZRVP2CimZWYWYWZzTWzf8XJ +82Mv/2pJl0g6RNJcSWsl3RVJV5Ku82mvlPTXaJlLOlnS+z7cNEl7++sPAV1xS8s3ShoVCwKcI2mJ +pK+ieUlzGSTF53+78QxJLX0exvrzxpLGeFm/kHSPpCZJ4vxMUnQcromkiT7v8xTZ3VTSd3x9W+fd +Toq4FUt6yJfNZ5KujbgVeHlWSVoEnFBDPhOmI+lG4AbgLC/fDlunqK7+ezmv8fcx5h41fHWs3ArO +tSUlJU+bmRIdwI24794+BPbx1/r484eB0RG/FwGLgDXAc0DniNtg3Nzretxin1eBkRH3kcBHwFrg +RaBbxM2AXknkWwKMirtWALwP3AQ08Wn2ibi3B74F2vvzk4B3vb83gL4Rv4uB/wPeA0qAwri0XvPy +bQK+Bs4EBgLL4uL4JTDP+3mgpKSkr6QX/L15SVKryL07XO4duE7SHG37DrFmMtAC+T7wOTDd37TF +wDFpTuMHwAKgFBgPPA382rtV9lSA1r6CDPM3+Sx/3tq7v+Ll+453b+SvLQS648zxf+DPj/F+JgIP +RGQZBuzq3a4EvgAax7fySNKa9GlOB37jz6/AmaHpBBQBfwYe8277+ApxlHe7A9hK8lb6S8AM3JbN +XeLcuuFai/cAjYFjcRX270BboDPwJTDA+z/fl0M3oDnwTCRvvXE9xkFAIa7yfgw08u6fRetAJO2/ ++LT7+rT3zkAZTCBJD8Tfj55Rf0Ab4E3gpoi/PwL/AFrhlsc/B9zi3Y4m0lMh0mvy938zbqWigFuB +/0Tu+8dixe79AAAgAElEQVS4l0UjXP3aCOzl3R/y96K5L68FwAjvdgnuhdoZV/emkaSnkkI6lXU0 +SRnV5F5d/f8lMBfY05/vx7ZnrwKYhHvGugBfAYOrkwG4CrjNX7vd5+lh4AZ/bRCwCtcjLwLGAa96 +t3Y+36fi6ujPcO+P8737Kbj63dvn5RrgjYgMVXpWket7+7LvlsDtxlgcwAP4d5Q//wnwgv99IO5Z +O8TXk+G+HhVF6tRsf7+bJCmjCqBH5DxRvZzpy6GTT+8d3LPXGJgKXO/97g6sxo9q4N7pq4G2Kb2f +6/qCT5LBJl7YvskKIU3pfOYrUh/cxl1tqapUzgFmxYWZCZzrf78C3Bjn/gpwdeR8DDAlcn4iMLsa +mdYC+8U/kCRXKn8GJkXOP6TqC7gT7qVZAFyPf7l6t+bAFpK/UFvhXmTz/AM0GzgkTp7dIv5XA6dH +zp8GLve//w1cEnHr7dMuAK4D/hZxE24Bxfei9yniHku7U+Tam8CZGSiD6pRK5YvC+3vAl9XP4/x9 +Q9UH9gjg02oe3qhSeSni9l1gk/89AFgRl85juJ5Dgc/T3hG3i9hWr6cCF0Xcjk1Ut7xb/2TpxNfR +JGU02suyNnJMTbH+zwdOrKbsj4icPwH8qhoZHsIpn8U45bgE9/KLKpX78UrHn7fwsnfFvahnxsW7 +lG1K5QW80vbnBbiWf5f4uhIXx1G+7BsncLsYWOB/fx9YFHGbAZztf99DpBETKbtYg+4z4LxkZZ5I +viT1cmjcsx2di74UeNb//hVuhCMa/4vA8OpkiB1pH/7SttVfN/jjQn8tY5jZB8DzwNXAvsBhkhbi +WlFL4rzHKmOMpWzPl5Hf3yY4r9xMTNIoSR/6buI6oBjXGqgRSbFVclF7Zt2AF/3QTBnuBVuKe4lf +BBwn6V+SWpnZZlw3f6ikjyV9JGlwLCIz22Bm15jZfkBHXKvx73FifBWXt/jzWF47U7Usl+Ae7o7x +buZq4VKqlnMsz3vgXmoFwEuSYrsIbQVukLTA5/XvfihtLfCpT2sBbqVf5T2LlEE6OAE3//SXiLzt +cYrrnYg8/8Q1YJLxJ0lzgJ/iFCKSWvt4m0v6F9Azlg9JV0v6GDc8cxiu/hThevwxovW2M1XrbXwd +jxLvNz6uVHjCzNpEju/7oa3Zkj7w9X+9pFLc6MCDfiilC/BpLH/x9ZOqz9Vmatikz8yWAp/gGkoL +zWx5grxG6+EmnJLbncTlED3vBtzp73E5rj42xb1MY0yUtCD2/Plrq3GNqAUJ8tfJu4NrrDaT1E9u +6H5/XO83lvYvYvXLv0f28DLHqGrauHZ8CeBl7wec6e/fYT4P3/PP36XeLSbPt7i6OSYufwnJxJzK +n4GDcdr3Hv/7zxlIJ54bgQuBc3Fjk338Ef9hZFcgWhmttglKGoDr4p9uZq3NrDWui13jmmEf9ibg +ZDP7JuL0OXA5cBDwoY+3BTACp2D+hRvuuFpSc9wLaCCuFTwEuEfafs2yma3F9bo6+xfcjrICV/lj +dAPKcBU13g3cCyX2IETLuAz4Da5ldSTwU7mPV7v6/O6NexFMMrM2uJb2fLYN0R3p4wbAl0F1L/gd +4T7cS+SfPl5wL4XNuPHw2Et1VzNrlTQW19M5EFf/d5N0FG7oZobP9ys+L10k7YMbA/+udz/cp1nK +9uUdq7dfECkDti/7KCvi/ML2z0BtuAI31NQLOB2nMK/FjRjMwTXwluLqZix/SevnDvAQbt+liQnc +qtRDSS1wdWM5rsy6xvmPlstS4GJf55bg5joKzaxPLDrcUNbe+OfPXy/E1ek/E8mfz+NpuB4+ZlYB +PIlrQA4FnvdKL5b2LZH61drMdjGz6PruWr+nEnAnrkzuwim3+cDxwFqfvw9w3xfGP3+HkcL9y4RS +6Wdm55nZNH+MwGnFjGJmn+Ae1pbAFnPfxfwV2EvSWZIKJf0IV7knpynZXXAP/xq5ydwbfPrJEICk +Lrju/rle7ih/wc39NPN+20s6GTfm+xvc8NsHwP/DzQEUAK+YWZmZLcaNnx/qw94mqY/Pe0vcOO4i +M1sXlSdFHgeulNRd0i7ALbghr9jDcoKkYyQ1kpuMLwH+48OuxLXMMbOVOOUo3PDCR7hWWTvc0CS4 +yn6a3IKIk3H363ifvw+AU+QWYBT5MqgpH40kNYkcSXvOZnYZrkc0WVJT3+saD4z1vRYk7V5Diy32 +sW8jL9s63P17xp9PxI2fb8Yp+idxD+8xuMndfrj6cYukXXzL9krcUA/e/+Vejta4uYVkvAlslvQr +f28G4urQ49WEqRbf2zweNwxnuJ7iKbgXeEtcw+f/4YajrgNeNrMy7/YZSb4rS5EncK3mpxK4PQ6M +kNRXbiHFrbjh78+BKcA+kv6ffx6uwBm+jXEvcI1X8gJaSTo9Lv7Yvr8Tff7A1c+ncHMwh+MWCfwA +N5TakqqbDj6Om98chuutxxgPXCIp9ty2kHS8V4qpUvmMVYfc4poBuB4f/r2xATgAp5TxednX1/FT +cENlR+F6b5Xvl2Tk4+qvKPHaewouT7HrH+OGxUbhWn+jgBMiL9VE2n9HWgT/8sdC3MOymcTDafFx +DwI6AE/Lrbr5WtI873YnbiL4YVxPaybuJnYws9dxQyp/wg0RrcG9mKNDVsvZNrTRHDfctQ5X2bvg +HoJkea3u/EEv02u4CrkZ16PCzBbi5q/uxrVeTwBO8i8SgNuA631X+ueRuLvhKvMsXEtoo3f7jf// +Eq43dxHbKvJC3MvqcdxDsIaahwb+z8sbO6YmyW+Mi3yc/5DUGNfLWATMkrTey9U7SVjDLWCbg6tv +K83sQ9ww4Wrv/iXu/p+Em3e8Dld2w3F1dndc2W7GDf29BjxiZhN8GuNx9W4u8F+2vey2F8Y1rk7C +KYHVsXTM7ONkYRLwI21bqfg1rq7fAryFq3uxCe5VuPq/zufvD7g5kPMkbcDdt1U+fzXVvWT5KfGN +1ZjitojbVNyc27O456AHroGGma0BzsBN8K/G9bBmRML+A1dP/4br0SwA/izpgkjya7zflT5/+LxM +wd27n+Oe7Sdw88pHRd41mNlbuOe1E24INXb9Hdwoy91+eHUhcN4Ols2NwEP+GYtXhtE4evj8H4FT +ZPf5XnkxTmlgZnNwde8a3BTGr3B1uYCq75fEpDLxsiMHdVj9hdPuXwLvVeNnHO7Bexc4IM6t8sNI +f34OMC7deczGgXvhvhc5Xxvnvsb/vwsYFrl+P/DDXMufQv52wb0QT6mP+fOyFuN6awPrS/5wDYa7 +/e+B+EUmwLr6kD8vYyf/vz1uKG9APbp/B+NGV2ILdv6I6+2nLX9p76mYay3shWtpXYZbwfJKisEn +4JZfJkTSENxa8b1wiwHujfOynKrjpntQ97HjnYUvJXUEkLQb23ony6k6NrzT51lSI1yX+mEze85f +rjf5i2FmG3Grig6h/uTvKOBkue+qHgcGSXoYWFlP8oeZfeH/r8JNph9K/bl/y4ClZhbbjuQZ3Pxt +2vKXqe2ED8atwjoA13U+N5VAZjYD13VOxim4iTrM7E3cuGfHiHvlh5F+2OIs3Fr4fERUnSuYBPzY +/z4PN0QWu36Wn9PpAeyJG5bYmXkQNyl/Z+RavcifpHZ+dQ2SmuEm5OdQT/JnbjVhVzPriXu+ppnZ +cNy814+9t7zNn6Tmfs4wNtE/GLfMvL7cvy+BpZJiw7ffx81Tpi1/mTAo+TBuvPJdts2lGF4Z1JF4 +Y5Kx8b0vAcysXNKluDHvAtxHitVbVNsJkfQYbmihraTPcev0bwOeknQ+bnXKmQBm9qGkJ9m29Pgn +5vupOyNyK6HOBub5eQfDjd3eDjyZ7/nDjZdP9CtkCnC9sak+r/Uhf8m4jfqRv4645eyGez8+amYv +yW00WB/yB24U6VG/YOVT3MrSQtKUv7RtJ1wZofQRzpRCrSL2K10mm1nfBG6Tgd+a2Ux//m/cB1Oz +E/jd2W9sIBAI7JRYHbYTzsTw1/tUXaqXTnZofC/Xk2KZPEaPHp1zGXaGvD3xhHHIBQ/y43/8OKMy +jfjHCMbNGpeS32+2fMPRE47mvL+fxzdbvmlQ9y6av8PGH8ZXp/0Au/POnMuUifzV16OupE2pSJos +aRLue4MP5b46nRQ7diQqkn93MAn3cSOSDgfWmxsjDDRQevaEr1ZXUJCx6UHHcb2O49+f/btGf5u2 +buLEx0+kR+sePHjKg7RonNadtPOKpo2aUrBm3bad5gINgnTOqYypawRJ5hIa4yx/3GdmL/iPghbh +1nvvsFXVQP2iZ09YtbqcAmVWqezZZk+WbqjuEyTHOX8/h26tunH/SfdnXKadnaaNmmJlX0OjtE/d +BnZi0na3zezVNMQxLAU/l9Y1nfrAwIEDcy1CxtiRvLVuDRVWQXlZYeYEAto1b8fqzaur9TN35Vze +Xv42n17xKYUFyeWpz/cOtuWvaaOmVJSVQWFm7022qe/3r66kTalImmFm/f0Xt9GBOeF6Ggn3OwnU +jvpcsXckbxI0KqrAKjLbK0hFqTz14VMM7zucxoWNq/VXn+8dVFUqVh6USkMjnT2V/v5/dbavAoG0 +U1BYjjI8p9K8qDmGsbl0M82Lmif08+KiF7lj8B0ZlSOfaNKoCaTYU+nevTtLllRnbDmQbrp168bi +xYvTHm86eyptqnM3ZyU3EEg7KqiggMy2hiXRrnk71mxeQ/NW2yuV8opyPlj1AYfuXhdbifWLpoWp +91SWLFmSlpVHgdRRnYxFJyedM2jv4I3pJXAzUrCgGQjUBhVUkDnjENto26wtqzevpkureEvy8PmG +z2nfvD3NipplXI58wQ1/lde74a9A9aRz+KtHXeOQ9AOcqejY1/C3x7m3xe1V3Qn3BegdZvbXuqYb +yG+UheEvqH5eZeGahfRum8xwccOkaaOmEJRKgyMTOz9K0jmSrvfnXWP7BNQQrgBnlvs4nMn3oXKb +N0W5FHjXzA7A7T1xhzdOGGjAZGP4C6BV01Zs3LIxodvHaz9mzzZ7ZlyGfMIplfo3UR+onkw07+7B +2eqPLQ/+Grf/R00cCnxsZkvM7QHxN5wBySgr2bYJVkuceeYyAg2abA1/NS9qzqbSTQndvvzmSzq3 +7JzQraHilEpFUCoNjEw8iYeZ2U9xO/9hbpOa6tdYOuKNRS5j+81gxgN9JK3AbVB0Rd3FDeQ7KihH +lnml0qKoBZtLNyd0W715Ne2at8u4DPlE5fBX+PixWkaMGMENN9yQkt8ePXowbdq0DEtUNzLxJJZK +KsR/qyK3BWtFmuK+GphrZp2BA4E/xcxUBxowBRUoC8NfzYuas2lr4p7Kqs2rglKJo0mjJijMqWSN +6dOnM2jQIHbddVd65tA0TiaaEONwW9h2kHQLcDpui8+aSGWDraNw25hiZp9I+gz4Dm4Hwe248cYb +K38PHDgwfLRUT1FBRVYm6mvqqbRv3j7jMuQTTRs1DUoli7Ro0YKRI0cybNgwbr311pTDTZ8+nenT +p6dNjkzs/Pgobk/j3wJfAP/PzJ5MIWgqG2x9BPwPgN+cqzduP4CE3HjjjZVHUCj1FxVUZGX4q7o5 +lTD8tT1OqdSPOZUePXowZswY+vbtS3FxMRdccAFfffUVxx9/PK1atWLw4MFs2LCh0v+kSZPYd999 +adOmDYMGDWL+/PmVbnPmzOHggw+mVatWnHXWWZSUlFRJ6/nnn+fAAw+kdevW9O/fn3nz5qUkY79+ +/Tj77LPp0WPHFuIOHDiwyruyrmRi9ddIM5tvZn8ys7vN7CNJt9UUzszKcau7XsLtRPY3H/ZiSRd5 +b78FDpE0F3gZt5dK+KiygaOC8qwMf7VoHOZUdoSmjZqiivqhVACeffZZpk2bxoIFC5g8eTJDhgzh +tttuY9WqVZSXlzNu3DgAFi5cyLBhwxg3bhyrVq1iyJAhnHTSSZSVlVFaWsqpp57Keeedx9q1aznj +jDN45plnKtOYM2cOI0eOZPz48axdu5aLL76Yk08+mdLS0lxle4fJRPPuNElnx04k/QlIaVzAzF40 +s73NbC8zu81f+4uZ3ed/rzazk8xsfzPra2aPZ0D+QL6hCshWTyXBnIqZsebbNbRt3jbjMuQTrqdi +aVMqUnqO2nLZZZfRrl07OnXqxIABAzj88MPp27cvjRs35tRTT2XOnDkAPPnkk5x44okMGjSIwsJC +Ro0aRUlJCTNnzmTWrFmUlZVx+eWXU1hYyGmnnUa/fv0q0xg/fjyXXHIJhxxyCJIYPnw4TZo0Ydas +WXUtvqyRiTmV04BJkiqAH+D2PBmZgXQCASDLcypl2/dUNpVuoklhkxoNSTY0mhQ2SWtPJddWXDp2 +7Fj5u1mzZtudf/PNNwCsWLGCbt26VbpJYo899mD58uUUFBSw++5VF7VG/S5ZsoSHHnqIu+66C3AN +ltLSUlasWJGRPGWCTNn+ugD4B/AGcJOkNmGYKpApsjX8laynsqFkA8VNghHueBoVNKKgIn09lXyh +c+fOvP/++1WuLV26tFKZLFu2rIrb559/zp57ug9nu3TpwrXXXsvVV1+dHWEzQDqbd+/gVmG9A7wC +7AqcELkeCGSGguwMfyWbU9m4ZSOtmrbKePr5RkNVKmeeeSZTpkzhlVdeoaysjDFjxtC0aVOOPPJI +jjjiCIqKirjrrrsoKyvj2Wef5a233qoMe+GFF3LvvfdWXtu0aRMvvPACmzYlXiASxczYsmULW7du +paKigi1btuRkLiZtT6KZ9TCznnH/Y0cwJhnIGMrmnEqC1V8btoSeSiIKCwqdUqkHHz/GW/StzsJv +7969eeSRR7j00ktp3749U6ZMYfLkyTRq1IiioiKeffZZJkyYQNu2bXnqqac47bTTKsMefPDBjB8/ +nksvvZQ2bdrQu3dvJk6cmFK6r732Gs2aNePEE09k6dKlNG/enOOOO64Oua4dSpe5aUmDzGyapB8m +cjezZ1OIo1qDkt7PQOCPQBGwysyOSRKXBVPaDYPOIy/nzP/Zk7FDL89oOnNXzuXcf5zL3EvmVrn+ +0icvMWbmGF4a/lJG08833l7+Nvv0OpwWq9ZDy+q3WZIUTN9nmWRl7q/XeklDOpsQRwPTgJMSuBlQ +rVKJGJT8PrACeFvSc2Y2P+KnFc6O2GAzWy4prOEMoILM7/wI1c+phOGv7ansqTSw4a+GTjpN34/2 +/0fEu0k6bfsQ21FpUNKHiRmUnB/xMwx4xsyW+7Sq39810DBQdlZ/NS9qnnBOZcOWDRQ3DsNf8RSq +kEIjKJUGRuafRMcfU/CTikHJ3kAbSa9IelvS8HQJGMhjCsqRZefjx0RzKmGiPjGFBYUUpvE7lUB+ +kK0ZtHTtW9kIOAgYBLQA/iPpP2a2KE3xB/IQqQLL0kR9wp5KWFKckEIKQk+lAZItpZLKDFwqBiWX +AavNrAQokfQasD+QUKkEg5INhCzZ/op93Li1fGuVDx03bNlAt1bdkgVrsBQiKgQFGdoLPZAe0m1Q +Mp0fP84jsfIQ0DHB9XgqDUriDFGeBQyN8/MccJc3rd8EOAz4Q7II02EcLZAHqByy8PEjbOutRJXK +upJ1HLjbgVlJP58orIByZW+MPVA74hvcN910U53iS2dP5cS6BDazckkxg5KxJcUfSbrYOdt9ZjZf +0r+A94By4D4z+7DOkgfyG1VAFlZ/gTPVsmnrJnZtumvltTWb19CmWZtqQjVMGpkoL3Br/wMNh3Su +/lqShjheBPaOu/aXuPMxwJi6phWoR2Tpi3pIPK8SjEkmprACygvC0FdDI/RMA3mPlJ3VX5B4Bdja +b9eGnkoCCg3KwxumRsJ2woHAzkaWVn9Bkp7K5jW0bRZ6KvE0MlEeOipZY8yYMey3334UFxfTq1cv +xozJzYBO/hvlCQSyZPsLts2pxKiwCtaXrKd1s9ZZST+fcMNfuZaiYfHwww/Tt29fFi1axODBg+na +tStnnnlmVmVI2y2XNE/Se8mOdKUTCGxHQUXWhr/ieyobSjbQonELGhWE9lk8hUa96ankw3bCo0aN +4oADDqCgoIDevXtzyimn8MYbb6SnAHaAdLYjTsTZ/XrRH2f74wV/1IikH0iaL2mhpP+rxl8/SaXJ +jFcGGhgqz4rtL9h+TmXV5lW0b57SxqYNjvrWU8m37YRff/11+vTpk7b8p0raV39JOtbMoov2r5I0 +G7iquvCpGJSM+LsN+Fe6ZA/kN5bF4a/mjar2VJZuWMoexXtkJe18I909Fd2UnshsdO2sIce2EwYY +MGAAHTt2pG/fvgCceuqplRPo0e2EwfUgxo0bx8yZM5FUuZ0wUO12wgDDhw/nlltuYdasWQwYMCBl +WUePHo2ZMWLEdqYYM04m+uySdJSZveFPjiS1HlEqBiUBLgOeBvoRCBDbTyU7w1/FTYrZULJtmGPp +xqV0adUlK2nnGwXlFZQrfebsa6sM0kW+bCd8991388gjjzBjxgyKirL/lVAmlMpI4EFvph5gPXB+ +CuESGZQ8NOpBUmfg/5nZMZKquAUaLqbyrH382K55O1Zv3mYce9nGZXQpDkolEYUGZfVo+CtVcrmd +8IMPPsjvfvc7Xn/9dTp16lSrOOpK2m+5mb1jZvvjbHLtb2YHmNnsNEU/FojOtdSTacBA3cjekuL2 +LdqzavOqyvOlG5YGpZKEmJmWhrb5Vq62E3700Ue59tprefnll6v0frJN2nsqkjoCtwKdzWyIpH2A +I8zsgRqCpmJQ8hDgb3J7arYDhkgqNbNJiSIMBiUbCMre6q/4nsriDYs55TunZCXtfEMVFZQVuGXX +hcpvS8W13U54xYoVHHDAAZXbCYOb8L/gggu47rrrOP7445NuJ7xo0SKaNWtG//79Ofroo2tM9/rr +r2ft2rX069cPM0MS55xzDvfcc0+1eUu3Qcm0bSdcGaH0T2ACcK2Z7S+pETDHzParIVwhsAA3Uf8F +8BYw1Mw+SuJ/AjA52TbFYTvhhsPu1wzijI7XMfaKQRlP6/Ulr3PV1Kt443y3VLPnnT351zn/Yq+2 +e2U87bzjvfeYN3h/9l6+pYoBzkSE7YSzT6a2E87EmEE7M3sSqAAwszKc8cdqMbNyIGZQ8gPgbzGD +kpIuShQkjTIH8hllZzthcMNfsZ7KlrItLP96Od137Z6VtPOO8nLKJcoranz8A/WITEzUb5LUFv/S +l3Q4sKH6II5UDEpGrqcy+R9oCGR5+Ou7b37O/bMv5tvyDfTv2ImiwmCHNyHl5VQUiHILSqUhkQml +8gtgEtBL0htAe+CMDKQTCABu9VdFlnoq5Z+U8ujjZUzd82ValJRy+hffYLcZCtZ4t6e8nIoCQk+l +gZF2pWJm70g6GtfjELDAzHb8c9BAIGWy9/HjF1MXUND8ME6ePwOrMJY37sGi5z5gr1P3zUr6eUXo +qTRI0v4kSvoEuMDMPjCz982sVNLz6U4nEIhhqoCK7Ax/bXzzI9Z3/i4AKhCf7jWYFY/s3KbIc0ZM +qYSeSoMiE827UuAYSRMkxZZ87F5dgECgLhjZs/1l8xdQsdd3Ks8L+h9F0dszs5J23uGVSllFWa4l +CWSRTDyJm83sR8BHwOuSupLiSq2aDEpKGiZprj9mSKp2mXKggZDF1V9Fa1bSuHvnyvPOPzycLl+8 +mZW0844tW9hSVBCGvxoYGbH9BWBmv/OGJF8CatwWL0WDkp8C3zOzDZJ+AIwHDk93BgL5hZE9219N +v1kFXbZZJe56TC/Kyr6gZH0JTXdtmhUZ8oaSEkobheGvhkYmmneV+2Ka2b+B43DKoiYqDUr6if2Y +QclKzGyWmcWWJ88iDKsFwPVUsmRjfZdvV9Gi+zal0qhpI74o6sayVz/JSvp5RUkJW0NPpUbCdsJJ +kBQbaF4u6aDYAbQFUpmoT2RQsjqlcQHwz1oJG6hXGOVZs/3VausqWu1Zdf+UVa33Ys2sj7OSfl4R +Uyqhp5IVxo4dS69evSguLma33Xbj/PPPr7ScnE3S+ST+wv+/I8GR1s2SJR0DjKCqcclAAyVbq78q +yipoU7GaNr3bVbn+bec9+Xbeooynn3ds2cLWxoWhp5IlTjnlFP773/+yceNG5s+fz5IlS7jllluy +LkfalIqZXej/H5PgSMUoUyoGJZHUF7gPONnM1lUX4Y033lh5pNNgWmBno4KKLAx/bViyns20oPEu +Ve1YWdeuaNnSJKEaMCUllNaTnko+bCfco0cPWrduDUB5eTkFBQUpmb+fPn16lXdlnTGztBzAD6s7 +UghfCCwCugGNgXeB78b56Qp8DByeQnwWaBi0ubGXXXz1xxlP55MX5ttnRXtud33mlU/afzqdmvH0 +847bb7cH/qedzV05t0avO/vz2r17dzviiCNs1apVtmLFCuvQoYMddNBBNnfuXNuyZYsNGjTIbr75 +ZjMzW7BggbVo0cKmTp1qZWVl9rvf/c723HNPKy0tta1bt1q3bt3szjvvtLKyMnv66aetqKjIrr/+ +ejMzmz17tnXo0MHefvttq6iosIceesi6d+9uW7durZRj6tSpSeV87LHHrLi42AoKCmzYsGHV5ilZ +mfvrtdYF6WzenVTNcWJNgS01g5LX41aS3SNpjqS3kkQXaEioAsvC8Nc3n63i6ybb70ffsk9XijeE +nsp2lJRQ2rgwfT0VKT1HLYltJ9ypUycGDBjA4YcfTt++fWncuDGnnnoqc+bMAapuJ1xYWMioUaMo +KSlh5syZzJo1q3I74cLCwmq3E5bE8OHDadKkCbNmzUpJxqFDh7JhwwYWLlzIhx9+yNixY2ud39qS +zj3q67wZstVgUNLcENuFdU0nUL8wsrP6a/OSVahFu+2utzuwCwUlQalsR0kJZUWF6fv4Mcem8fNl +O2GAXr16cdVVV3H77bfzs5/9bIfC1pVMfKeCpBOAPkDlwn0zuzkTaQUCFVn6on7r8lWoePueSvt9 +O7K1YgObV2+mebvmGZcjb4j1VBrYRH0utxOOUlpaSvPm2a+PmbD9dS/wI+Ay3IeQZ+DmSQKBDJGd +4TWvwnkAACAASURBVK+KL1dR3mZ7pVLYuJBlTXqxdFpYVlyFkhLKGjeqFxP1O0KuthN+4IEHWLXK +bXX94Ycfctttt1XZVTJbZKJ5d6SZnQusM7ObgCOA3hlIJxAA3PBXNlZ/afUqaL+9UgFY3e67rJmR +cJPShsuWLZQV1Y+eSm23E27fvj1Tpkyp3E64qKiIZ599lgkTJtC2bVueeuqppNsJt2nTht69ezNx +4sSU0n3jjTfYb7/9KC4u5oc//CHnnXceV155ZR1yXTsysZ3wm2Z2mKRZuJVfa4APzGzPtCZUsxyW +7rwFdk5a3tyB0796nwl3d8hoOm90PxsbfBz97zt3O7fpA64HiYGvhVHeSs4+m9/sMpujrrqHY3oc +U63XsJ1w9smn7YSfl7Qr8HtgNrAYeDwD6QQCQPasFLdYv5xmPROv+9/luKNoPfeVjMuQV8SGv+pB +TyWQOml/Es3s12a23syewc2lfMfMrk8lbE1Wir2fcZI+lvSupAPSKXs+UZ8/5tyRvG0p28IW20Sj +staZE8jT6esFdDrmOwnd+vzkaHpsnMuX735RYzz1+d5BJH8NdE6loZOJifpCSSdLuhz4KTBS0s9T +CBezUnwcbuXY0Ig9sZifIUAvM9sLuBi4N93y5wv1+cW0I3lbvH4xbQq7ZNxMy4bPN7BLxUZ2Ozix +ObpmbZox++CL+OTkK6koq6g2rvp876CqUilvXBR6Kg2MTIwZTAZ+jDMk2TJy1ESNVor9+UMAZvYm +0EpSRwINlk/XfUr7op5UVP8erzNLprzP0ma9KWiU/JHp98JNNN+4koXFB/PmNc9hFQ18jqCkhIrG +RWwu3ZxrSQJZJBPfqexhZn1rES6RleJDa/Cz3F/7MlGE0y88thZiZA6l4R3z4scrmLJgBQd1bs2r +y96oU1wrv/6WoU++wdTzB1FQhy+N082Sdz7ltaUzePmTlby06At+f9yBAAx8cCqPnX4knYubVfpd +//UKfrGhBZvfvZlXv584vts+/Dsdmrbi/J6DeG/9EsbMn8TEwy4DYOh//sgvv3MKB7XuWa1M7d6a +wspjhpF48MvRokML9l/7Cm9dN4lWY29k4R9v4It9vg8ti5m45FWWl6zjmv3OZPEnrzN95q0pl8f7 +65dw+wfPsHbLN1yz7xkc1eG7KYetLS+umM0Ly//LuH4X1ew5jlj+jnprNqX7Xc7Pnx7DvXIr44T8 +35rr25IlS+jRowdlZWUUFFTf/p04cSL3338/r7/++g7Lmyv+93//lz322INrr702ZzIM/nXVejj0 +sP+pe6R1sfGS6MBN0A+uRbjTgPsi5+cA4+L8TMYtWY6d/xs4KEl8Fo5whCN/jngWL15sBQUFVl5e +ntBGVZS//vWvNmDAgKTuW7Zssauuusq6du1qzZs3t969e9vvf//7GuNNF3/961+tf//+WUsvFWq4 +F7XXAXUJnDBCt4x4M/AtsBH4GtiYQrjDgRcj51cB/xfn517gR5Hz+UDHDOShJbAOOBP3AWcT4H+A +fdOdVg1ydAfKgcLItfOA19IUfzcff0ES98+AQVnIZznQMwV/Fan4SxBuAnBzjvM4GniolmE/rk5G +n4dj0izvDtUzL8NHwE8j1/b1z2g50LW68E2bNl2Za6XW0I6mTZuuzERdz8Scyh04BdHczIrNrKWZ +FacQ7m1gT0ndJDUGzgImxfmZBJwLIOlwYL2ZJRz6qiO9cdr6SXNsMbN/m9n7Pu3zJM2Q9AdJ6/xq +tCMl/VjS55JWSqr8mEFSsaSHJH0l6TNJ10bcJOk6SYt9uL9Kis1Bver/r5e0UdJhkWC/l7RW0id+ +a+VoWvdLWiFpqaRfy38xJalA0hhJqyQtAk6obQFJutDne7Wkf0jqFHEb7FfxrZP0J0nTJZ1fXXRJ +0jhPUsLxDEn9fVl/z59/R9JLktZI+kjSGUnCHS0p3lDXgZLmenkf9/UvlXweKektH+5NSUdE3Lr7 +fG+Q9C9ge6NhVeWKT2c3f30R0AO3VH+jpKJkUSSJt6ekqT7er/T/2zvv+Ciq7YF/TyB0EghF6UWK +KCBSFUERFRUVVHzAw0rxARZs+ENERPH5niJYQLEAUhWfCirtIR1sCD6qIggISJHepaWc3x/3brIJ +2c0mu8kmm/v9fOazM3fu3LJzZ87ccs4RmSIiMV7nK4vINHvugIiMTH15+u3MB5MxwsjD/cBE7wi+ +noXTp09fiLFUPgI4CGzFLPRJwnxUCRALjAP+xAyP/xPzQSSYedxvVFXSbpgPwtNApTThLTAC7yKM +FZCf0px/EvjK7he2ZfsD2Au8CxSx59rY8gyw5yalSacecAZIAE5iFMMFmAC8lCaN/wMOYFyq3wG0 +x3xUHAIGeqUZBQy0/9NB4D9A6fTq72uz/3noCbWUApbh48s3gGtvAjbZP/EZG9Yb+IdXnLcxJvLX +4mPoKwR1KGlv7ARbplJpzt8PnMMIOAFewsz1jAKigRswvbRiNv4k4AugGKZ3sAnobs/1AH6z4cWA +adgvWlJ6EpJO3j1s3n2A3V7nvwBGY+yulcW4XX7QnusDbAAqAqWARWShpwK0tf/PZba+I4Gl9lxZ +4BhmUUUU0A84C/Tw83+n2wMhzdeyJ569JzuAJja8GOZh99yPy2z5Lrbnx2N7KsA1wB9p6rgcuMD+ +Jxs87S2DepYGDgPdbD272uPS9vz3mKHgaKC1bQ/p9lT85eNVRp89EV/3yZ67CLgOM39aBlgCvG7P +RWFcTAy37aUQdng5o3bmqwyY3kpdm/YfQBV736oG8Cz4bZ/4b9up2kqasv0bWOzj3HaMkdqimHZ7 +kde5FcDf7P4bwJcYwVYc+Ap42atNxQP/svevcEZt2Ue7jAcGYYRrL9smPrL/1SWYEaBqNv5jto1V +sHm+C3ycHe/DzG7Z8UKegBEsAzGS/kngyXBXNAv1qAt8aB+Mc7YRlfNqIJu84ta3jb+sV9hBoKF9 +uM4Cdb3O/QNYZPcXAH28ztWx+UWRMvwV5XX+fuA3r+Oi9qEtb7cz3o0a87JbaPcXklpA35A2/TT/ +gS+hMhZ4xeu4uK1jVeBe4Ls08f8gdELlGVuuel7hnfF6Cduw94DBdj8jofJ3r+NXgdEB1PMeYHma +PL/HCLYq9h4W9Tr3Eb6FSnr5nCPlRexTaHidP44Rakfsb08fcTsC/7P7V2IWuZx3/320s0SgvL+2 +AjyLebneCHyNeUEm2f8so2fBZ/vECP302vYir/L6Eipj8PHCBX7A9ADA9LSes/u1MUKmsD0+CdTw +uu5K4HevNnUGiPZzjwIRKn+RYuWkhP3fmnrF/wnjnBCM8L3W61wF22ay9EEfyi07hr+2YRpHITK3 +pDgkSAAKlIGgqptUtYeqVsUIjYqAt3MC72G30/aag2nCSmC+qApiXqwedmBWrWHT3ZHmXLRN/79e +9SotIvOAV4CyIhJr8zxto/xot2jgTztkcQTzcvUYrKpI6tVz3vlmhlRlVtW/MC+ySunkAaZb76nH +RhFJEJFEO6TSz56KscNXm0Tka0/97DUDRWQz5ov5aeBTVfU2tFUNuMLW2VPvbpgXUSB438tTmPsW +SD3T/n87MC/P/9qy/iQinuU1+4Dr06sf0AroYYft2tl8DpHSRgKho6rGqWpp+zsOQETK2yG9XSJy +FJhCylBcZWCHqvpakL3Xq+6nbZ1K2HSjRGSViHiGqKOAYUBP4AnM1/8kr7SWYuZXMnoWfLXPqqTf +tv0OK1oOYl666VHBngf4GKMftx34BjNc9Y2IlMP0Fn6z7TYec4/L2OvuxgjPdSLSLoDy+OKQWgmB +facA+73Oe94pYNr8F542jxEy8QTQ5kUkVkQ+s+3tFxFp4Xm/+Hv+PO0zo/RDKlREpABQUlVfTLuF +Mh8/+WeoQJkVVPU3TA+sfhYuP4i52dW8wqqR4ip5Tzrn4oG0N+8ZTK/mGeAopieIiFyCedjbkbKw +oIzXC6aUpizx/hPzFe2dV1ZIVWYRKY55wHankweYl5eHNpivrwKY4Z6HbXgfYIGq1sUMe3hsfxez +9aqH+XI7DdzhJYzAvIiW2Dp76h2jqo9ksX6B1HMPpifpTVXMC/NOzGRoc6CtiFyFaZN/pq2fvX9l +MV+tN2Mc0Hny2UXg+Fqj+y/M/3apqpbC9LA8cXcCVe1zk1kew7zIPMRiekAXYf6bW4HpmPsmmF7M +jXbf17Pgr33uxPQGfLVtfywAWohIKiEtZo6yMuZ+AMzHfIAVxPRSuqlqc8wznIDpTRYAngPeU9VY +e/+utWX33L/07oWmExYMfwA3p2nzxVU1Y5MO8BYwR1XrYZ7Bjdj3i4/26Xn+/NUvmZAKFTXeG68K +ZZqZJBAFygwRkboi8qSnEYpIFeDvmK6yz8vSC7RfgZ8CL4tICRGphvmSm2yjTAWesBO7JYCXbdhh +TENOwoyLdyRl0nMfcLvd74BpsImquhLzZTNVREqKoabYyWxbjn4iUklESmMmFjOikIgU9toK2PJ1 +F5GGIlIY8+Jarqp/ALOB+mKsKhQQkUfw+npS1b2qusbun8SMwYMRilNtelO96lcG4wU0wf7HW4Cn +bD362DizgDoico+IFBSRaBFpKiKpHL5lAX/1nAPUFpGutp5dMA/eTPsR8hNmrq0AZqL9YsykKpj7 +6H3/pmMmmmNs/cbZfELh+askZujmhG3PT3udW4F5Gb4iIsXs/W2ZUYIiUhkzgTzWK7gYxmsrmGGp +P23v5jZS2uc2m99oH8+Cz/apqntt+m/4aNs+UdWFmNGTaSJyie1lXWHzHa2qW228BOAzjHfZUhgh +g+09nAQa2F7LROAu+9XewaaNqm7HzAen1a8D88xWFt8LLTLL+8C/RKQqgIiUE5EOGV0kZpFGa1Ud +b8ucoKqeOVDP+yVt+/zExtuO7/olkx3DX2tEZIaI3Csid3q2bMgnPdJToMzMEIKHE5iVIT+KyAnM +WPk6oL+fa9J+iXgf98MMq/yOmW+a4rmpmHmbyTZ8q43XzyuNl4HvMHMtni+3eMz8CZxfv68xX40b +MILpM8CzymOMPb8W89Kb5qc+HmaTskT8FDDEPqSDMS/D3ZiXZlcAVT2E8aHzGuYL72Kb19m0CYtI +daCRrWcNzKTpacwQqqd3U4iUe6qYhzMas6JngIj0sMKpnS3DHru9glmxkxE+vyAzqOdhzNd4f1vP +/sAtqnrEfvnHYu5jQ8w8UzzmS9vzgvS+f0u88mmDWYzQNZAyejFTzOowz+a5ty8CTTC925l43XP7 +wXMbZv7gD8z/3NlPHp5yvIERTt7lKoCZz8F+3HiGT9K2z4WY9056z0JG7fM+THtIr21nRCdgMTAX +83xPAsaoar808aZi5o8E8/z3suGCcXO+HPNlXx3zTFYi9RCVRyE7LYvs9XtFZH8659PD3zvlLcw8 +7zwROYZ5R/l92VtqAAdFZLwdvvxARIphVDP2QbrtMz2Fcz+lDvEkDaYbn3b7MJNpDMEIhFV2u8nr +3ECMtPyVNEqWBKBAmVc2jABZ53V8OM35Q/Z3FKab7gkfC9wZ7vJ7lUdsQ7wmTXgJzIujY16uXwZ1 +j8H0bttESv0wy9DftvttgBl2/0gk1M+WsYL9LQesxqzei5T71wTzgdPUHr8BDA1l/UJupkVD4Kve +8rqqvu4dICL1SBnfqwwsEJHaamuLeXlV9bqkMinjtXmdfSJygaruE6PD4Pna2U3qceiw19kOC/yI ++TL3DLcs9zpfEPgcmKyqX9ngPFO/QFHV4yIyB2hK5NTvKqCDiLTHfNGXFJHJmC/wSKgfauclVPWA +iHyJ6QFEyv3bBexU1Z/s8TTMfErI6pcdVoori8gXYpSb9otRrKqc8ZXnJ5VOWEf8j+8FokCZVxBS +/wczMOPuYJYnfuUV3lVEColIDaAWZqw8nFyJGcrbj/my7aiq3sNfHwIbVPUtr7C8VD+fiEjyyjwR +KYpZFruaCKmfqj6rqlVV1TNEt0hV7yXFkCzk4frZuSXPCrfimGHV9UTO/dsH7BQRjzfe6zDDcqGr +XzZ0r+YD3TErKArags7PZBpDMOPqazDdrdhAu2Kko0CZ1zbM0sY9mHmIP+z/WRqzimUTZsKylFf8 +gZgJ3vOGBHPbhvnSTbT3djV2eBMzORoJ9Wtg67QaMzfQ34ZHRP3S1PUaUoa/IqJ+mDkHT9tcT4oS +dkTUz5b3MswH+BrMPF5sKOvn151wRhPsqjo9nWvWqGqjAMLmk3pNtWAmogZhhkoOqqqKyD+BC1W1 +l4iMAn5Q1Y9tGmMxS+PSK0eol/A5HA5HvkCz0Z3wbXbriVnmeLfdxmLMN6THIbu0s4Dd7sEocqUt +9A2q2tBra2B/Z6rqAU2RdmNIGeLK1PheuL8IsnMbMmRI2Mvg6ubq5+oXeVuw+BUqqtpdzcR7NHCJ +qnZS1U4YxUJf6617YCbT92LWpN+FGb4JGDtR5OFO4Ge7n6fGLx0OhyO/EejqryqaWlNzH6lXWSWj +qjswCjPBMEyM//kkjO5Cb5v2BhH5lBSTBA9pKESrw+FwOEJCoEJloRjz3VPtcRfMpE4yIvK8n+tV +VV9KE/8u4AXM8uBmqrrK6/SvmBVECRiN1332msYYzfYk4GtVnUc+pU2bNuEuQrYRyXUDV7+8TqTX +L1j8TtSniihyB+AxibBMVb9Ic/6pdC4rjpmPKaOqJdLEr4sRDu9jVsissuH1MKufmmF1UYDaqqoi +8iPwiKqutOv/31LVr32U13ViHA6HI5OICBrERH1mlB+/x/QclHTmMVR1hFehSmIMznXH2N8akU78 +TTZu2sIn66IA28VYp20uIjswxipX2niTMPZp0hUqDocj71C9enV27Miq0WxHVqhWrRrbt28PeboB +CRUR6Yyx5bQEs/R3lIg8raqfp4kXh/GfcjfGKFljVT2SyTJVIrXhRo+tmQRSW23Nql2viEIVPvsM +xo6FLVugXDm48Ubo2xcq+DL2HWJ274YffoCzZ+Gyy+DSS8G/HVOHIzU7duwIycojR+Cc/z0fGgLt +qQzCzHvst4UphxmWShYqIvIaZqXWB0ADVT0pIvNFJF1dFFWdGYoK+OOFF15I3m/Tpk3EjYWePQv3 +3AO//QbPP29e6Hv2GCFTvz4MGABPPAHRobKLmoaffoIXXjACpXVrKFwYnnsOihWDwYOhSxcnXByO +3M6SJUtYsmRJyNILaE5FRNaragOv4yhgbZqwJIwGuGeILPkUZqI+XT/1IrIYeMprTuUZG/9VezwX +o2G/A+MStJ4N74oxUtjXR7oRPaeSkAC33w5Fi8JHH0GhQqnPb9sGffrAvn0wZgw0axa6vOPjYcgQ +mDABBg2Cnj2hSBFzThUWLoT/+z+oWBHGjze9J4fDH3YcP9zFyFf4+s+DnVMJ1PbXXDHewB4QkQcw +5tDneEdQ1ShVLaqqJdU4SPJsJX0JFC/S2rg6TxdFjTnmYyLS3M7D3EeKfZp8x4ABcO4cTJ16vkAB +qFED5s6F/v3httvgscfgxIng892+Ha6+GtasMdvDD6cIFDA9k+uvhx9/NL2lxo1hhdMkcjjyDQEJ +FVV9GrNKq6HdPlDVLLvqBRCR20VkJ3AFMEtE/mvz2oBx1rMBI7i8dVEexmj2/4ZxxjU3mDLkVSZP +hpkz4T//gYJ+BjBFzPDYL7/A8eNmrmNGEOY1P/sMmjeHv/0NZs2C8uV9x42OhldegXfegVtuMcLP +4XBEPpmxUvwdxsnNIrsfLB6XnYUwzo1uBhDjDW4wcBzjsOl2r2s0zZbv+O03ePJJmDYNSpcO7Joy +Zcww1IQJpufSqZOZXA+UEyfgwQfh2WdhzhyTf1SALadDBzMcNnCgmWdJ8uUN3eHIp3Tv3p3nn/en +5pdCjRo1WLRoUcYRw0hArwa7+msFxuRKZ4xHtLuCzHs9cAewNJ1zW1S1sd0e8gp/F+ipqnUw7mNv +DLIMeYqzZ6FrVxg6FBo0yDh+Wtq2hXXr4JJLoFEjePllOHrUd3xVmD3b5JWUBKtWQdOmmc+3YUMz +BLZ4MXTuDH/9lfk0HA6Hf5YsWULbtm0pVaoUNWvWDFs5Au2peFZ/3a+q92EMPA4OJmNV3aSqm0nf +b8p5YdYeWHp6KvmGgQOhWjUzAZ9VihSBl16Cb781vZ5ateDxx+H7780cDcCZM2Z47ZprTM/m/fdh +3DgoWTLr+ZYvb3osJUpAy5Ywfz4kJmY9PYfDkZrixYvTs2dPhg8fHtZyBCpUojzLiS2HMnFtVqhu +/ScvFpFWNqwS+VhPZc4c+Pxz83IPxTLdunVh4kTTgyhVyui1xMZCXJw5fvVV6NUL1q83ei+hoHBh +Mww3YAA8/bQZlmvY0PSg/vY36N3bLI0+klnNJocjm6lRowbDhw+nYcOGxMTE0KtXL/bv30/79u2J +jY2lXbt2HDt2LDn+jBkzqF+/PnFxcbRt25aNGzcmn1u9ejVNmjQhNjaWrl27cubMmVR5zZo1i8sv +v5zSpUvTqlUr1q9fH1AZmzVrxt13302NGjVCU+msEqAp5NcwmusP2O2/wKsBXDcfWOe1rbe/t3nF +WYxRkvQcRwOl7X5jjJOqEhjfyvO84rXCOgjykbdGCgcPqlaooLp0afbmc+aM6qFDqufOZW8+Hg4c +UF29WnXBAtX//Ed19GjVG29UHTQoZ/J35B5y+/NavXp1vfLKK/XAgQO6Z88eLV++vDZu3FjXrl2r +Z8+e1bZt2+rQoUNVVXXTpk1avHhxXbhwoSYkJOiwYcO0Vq1aGh8fr+fOndNq1arpW2+9pQkJCfr5 +559rdHS0Dh48WFVVV61apeXLl9eVK1dqUlKSTpo0SatXr67n7ENZvXp1Xbhwod+yLliwQGvUqJFh +nXz95zY8y6bzA1J+VNWnRaQTxmsfmNVfX/i7xl53QyDpp7kmHjhi91eJyFagDlnwlRwpyo9PPGG+ +5K++OuO4wVC4sNlyirJlzebNDTfAlVeaob7ixXOuLI7cT6gUabOqDvPoo49S1jbY1q1bc8EFF9Cw +YUMA7rjjjuQJ9E8//ZRbb72Vtm3bAtC/f39GjhzJ999/j4iQkJBAv379AOjUqRPNvJTIxowZQ58+ +fWhqJy/vvfdeXn75ZZYvX07r1q2zVvAMCLXyY8C2v1R1GjAtZDmnJrm5iEhZ4LCqJolITYyeyu+q +elREjolIc4wrzPuAkf4S9RYqeZU5c8z8x7p14S5JzlCrltHOnzDB6MA4HB7CrRt5wQUpxkGKFi16 +3vHJkycB2LNnD9WqVUs+JyJUrlyZ3bt3ExUVRaVKqUftvePu2LGDSZMmMWrUKMCMJMXHx7Nnz55s +qROc/8H94osvBpVeoKu/7hSRzfalflxETojI8WAy9qWngrGEvE5EVmH0VXqrqmeNUr7SUzl+3EzK +f/CBmeDOL/TvD6+/7ibyHXmTihUrnmccc+fOnVSqVIkKFSqwa9euVOf++OOP5P0qVaowaNAgDh8+ +zOHDhzly5AgnT56kS5cuOVL2UBDoZPswoIOqxmrgWvIZ0RI4CWzCWEDuAsl+7z8CSmJM5yd4XZOv +9FQGDIB27YyGen6iZUuzWuzLL8NdEocj83Tu3JnZs2ezePFiEhISGD58OEWKFKFly5ZceeWVREdH +M2rUKBISEpg+fTorvExOPPjgg7z33nvJYX/99Rdz5szhrwDW4asqZ8+e5dy5cyQlJXH27Fni4+Oz +rZ6+CFSo7FPVX0Oc9zzgUlVtBGwGBgKIyCUYXZh6wM3AaC/z+PlGT2XpUrOsN8yrA8NG//4w4jyH +CQ5HeEhr0defhd86deowZcoUHnnkEcqVK8fs2bOZOXMmBQsWJDo6munTpzN+/HjKlCnDZ599RqdO +nZKvbdKkCWPGjOGRRx4hLi6OOnXqMHHixIDyXbZsGUWLFuXWW29l586dFCtWjBtDtXQzE/g1KCki +d9rda4ALgS8xRiOB5F5F8IUQuR3opKr3pmNQ8r8YD5E7gEWqeokNj1iDkqdOGYvDI0YYjfT8SGIi +1KljTNK0bBnu0jiyG2dQMufJLoOSGU3U3+a1fwpo53WsQEiECtCDFFfF+d6fypAhRnM9vwoUgAIF +zKq3ESOcUHE48hJ+hYqqdg8mcRGZD/j1pyIig4B4VXUmB4FvvoEpU/LPai9/dO8OL75onI/VqhXu +0jgcjkDwK1RE5P9UdZiIjCKdiXFV7efv+oz0VKwZ/fZAW69gX/ooEa+ncvw43H+/We3lfJAYPZXe +veHNN+Htt8NdGocjMslRJ10icpuqzhSR+9M7r6oT0wsPKGORmzC+669W1UNe4ZdgVn+1wAxvzQdq +q6qKyHKgH0ZPZTYw0tey4rw4p9Kzp7H+O2ZMuEuSe9i71xjA3LzZmHVxRCZuTiXnya45lYA8P2YH +IrIZY/beI1CWq7VILCIDgZ5APPCYqs6z4U2ACUARYI6qPuYn/TwlVL78Ep56yji+CsZwYyTSp4+x +S/bqq+EuiSO7cEIl5wmLUBGRmfjRB1HVXDuVnJeEyr59xhT955/DVVdlHD+/sWePMb+/Zg1UqZJx +fEfewwmVnCdcQuUafxeranq+UALLWGQYZnXZWWAr0F1Vj1snXb8CHrOe3j2YxqTuqTzuJ/08IVRU +oWNH43r3X/8Kd2lyL4MGmaGwcePCXRJHduCESs4T9uEvESkKVFXVTVnNLE1612P0TpJE5BWMbspA +K1RmqmrDdK75EXhEVVeKyBzgLVX92kf6eUKojB1rXO7++GP6vuYdhmPHjN7KokXGLbIjsnBCJefJ +LqESqO2v24A1wFx73EhEgvB2Dqq6QFU9zmWXY1ZzJWeZThkizknX1q3GGu+UKU6gZERsrHFn/Pjj +4Tcs6HCEknzpThij0d4cOAqgqmuAUHqC6YHx0eIh4p10nTljzNkPHuy+vAPloYfMENhnn4W7JA5H +7mP48OE0aNCAmJgYLrroorB5gAzU9H28qh5LY3cmw+/FTCo/fmzj7MEMsx2xcyhf2mXGmSY3fXXH +3QAAG2VJREFU66k8+ijUrm1+HYERHQ2jR8Pf/w433+xWyTkcaZk8eTINGzZky5YttGvXjqpVq9K5 +c2e/14RaTyVQz4/jgG4Yr421gVHAe8F4B7PpPgB8BxT2E2cxxgPkhcCvXuFdgXf9XKe5lXHjVC++ +WPX48XCXJG9y332qTz0V7lI4Qklufl5VjcfF1157TRs0aKAlS5bUnj176r59+/Tmm2/WmJgYveGG +G/To0aPJ8b/66iu99NJLtXTp0nrttdfqr7/+mnxu1apV2rhxY42JidEuXbpo165dkz0/qqrOnDlT +GzVqpKVKldKrrrpK161bl6ocGXl+9NCvXz/t16+fz/O+/nOC9PwY6Mu/GPAyRulwpd0vElTGcBPw +C1AmTXhZIMru1wR2AqXs8XLMMJwAc4Cb/KQf0B+f06xapVq2rOovv4S7JHmXfftUy5VTXbMm3CVx +hIrc+rx6yEvuhD1cfvnl+v777/s8n11CJdDhrwtUdRAwyBMgIs2sgMkqozDKj/PtsJpn6fDVwFAR +OQckcb6TrgmkLCnOU066du+GO+6AUaOMlrgja5QvD//8p1GK/O47Y4XAEfnIi6HxJ6xDsrbSIy+5 +Ex4yZAiqSvfuQZlvzBKBCpVp1mTLbgARuRp4B2gQRN5TgY6YxQIHgX+BMacvInUxk/cJRIiTriNH +4KabzIuwa9dwlybv06sXTJxoTNr07p0SvuHABt5a/hbzfp/HzmM7U13TvVF3xnRwNnDyKlkVBqEi +r7gTfvvtt5kyZQrffvst0dHRmatkCAj0G683ZsL8QhFpj+lltA8y72GqepkaJ11fAUMgMp10bdli +NOVvvtl4c3QET1QUvPeeWT23bx8kaRJDlw6lzYQ2VImtwty753J60GnOPHeGM8+d4fCAwyzYtoD5 +W+eHu+iOCCec7oQ//PBDhg0bxqJFi6hQoULwlckCAQkVNboh/TDeGl8ArlfVnX4vyjjNk16HxUmx +AdYB+ERVE1R1O8YrZPO8qqfy5ZfGH8ijj8KwYeDHcZsjkzRoAA88AP36n+D2T25nwe8LWNNnDc9d +/Rx1y9YlukA0BaMKUjCqIDGFYxjdfjR9ZvfhVPypcBfdEcGEy53wRx99xKBBg5g/f36q3k9O41eo +iMhMEZlhFR0HYibszwLjglV+tOn/U0T+wKwC+7cNroSZnPfgcdKVp/RU4uPh6aeNst7MmdA3Xf+U +jmB5+tlTfFWiPYknyrLgvgVULFnRZ9yba99Ms4rNeGnpSzlYQkckkBfcCQ8ePJjDhw/TrFkzSpYs +SUxMDA899FAQtc4a2Wr7KxA9FRtvAHCxqna3vlt+UKu3IiJjMSu9dgD/VtV2NrwV8H/qw6iliOiQ +IUOSj3NST+XkSbjrLrP/0UfOZHt2EZ8YT4dPOnBibzkSPp/AD99HZdgT3HtyLw3ebcCi+xbR4IJg +pgTDh6ryvz//x7yt8/jj2B/EFo7l1jq30qpqK78vndyMM9OS83j+87R6Ki+++GLO2P7KTkSkCmY1 +V4N0fNTPxcy37AAWq2o9G54rfdQfOQLt2hkf8++9BwUDXQrhyDT95/XnlwO/8FWXmTRvWpDBg8Hr +o88n7//0PhPXTuTbHt8SJXlr6diOozv4x6x/sOXwFjrW7UituFocPHWQyesmU798fcZ3HE+pIqXC +XcxM44RKzpNdtr8y0iX51v6eAI57bSeA48GsZQZqee0/Cky2+5cAqzHLjWsAW0gRfrlaT+XECdUr +rlB97DHVpKQczz5f8fkvn2v1N6vroVOHVFX1669Va9dWtcv5/ZKYlKhXjbtKR68Ync2lDC0Lti7Q +C167QP/9zb/1XELqip6JP6O9Z/bWph801WNnjoWphFknHM9rfsfXf05OKD9mxwZ8jtHQXw1MA8p7 +nRtohcmvQDuv8CbAeszk/VsZpJ+1fzqLnD6tet11qj16OIGS3ew+vlvLDSunK3atSBV+/fWqfnS9 +UvHzvp+17LCyuvv47mwoYWhJSkrSV799VS8cfqEu+n2R33i9Z/bWNhPa6Klzp3KwhMHjhErOk11C +Jct9fzvBHgwbMPMrAsRieiZY0/eDMT2i06Re4ZUr9VTi46FLF4iLM/7l8+iwdp5AVek9qzd9mvah +WaVmqc4NGQKvvAIJCT4u9uLS8pfSu0lvHpvr03lo2FFVFm1bxPWTr+ezDZ+xotcKrq1xrc/4IsI7 +7d+hQokK3PXZXZxLPJeDpXU4DMEMKAf76kyrp/KC17ktqtrYbt7LF3KdnkpCAtx3n/mdMgUKFAh3 +iSKbKeumsOPoDp67+rnzzrVqBVWrwtSpgaU1qPUg1uxdw6zfZoW4lMGRmJTItA3TaDG2BQ/Nfohu +9bvxXY/vqBKbsdvLAlEFmHj7RAoXKEzXz7sSnxifAyV2OFIIRqgE1VPQ8/VUDnod5wl/KomJ0KMH +HDoE06Y5nyjZzb6T+3hq3lNMuH0ChQqk/2cPGmQ8aCYlpXs6FUWji/LeLe/x8JyHOXnuZMYXZDOq +ylcbv+LS0Zcy7PthDGw1kA0Pb6Bn454+65se0QWimdppKucSz9Hp005OL8eRo2S0pPhJX6cwy4Lj +gspc5J/AfcApoIUa8/rVgJ8x8ybHgMGq+q2INCGTS4r91S1Yzp2Dnj2NPa9Zs6BYsWzLymHpNq0b +VWKq8OoNr/qMowpXXGF0hDzLujPivi/uo1yxcoy4cUSISpp5Dp8+zP1f3s/Ww1t5/cbXufGiG4Ne +Hnwu8Rw9Z/Rky+EtTO00leqlqoemsNmAW/2V82TX6q+MFrz681jxVkaJZ6SnoqrPAc9ZPZU3ge7A +n+RyfyrHjpmlqyVKOIGSU8zdMpflu5Yz9qGxfuOJGA+RL71k7lEg7+UR7UZQ/936dGvQjSYVm4So +xIGz4+gOrp98PR3qdGB65+lEFwiNvaZCBQox8faJvPbdazT9oCl31ruTBuUbcOzsMXYc3cHB0weJ +T4yneqnq1Cxdk5qla1IrrhY1S9ekWLRr1PmFUPtTyXV6KumcWww8hXHetVjDrKfy889mUv7aa+Gt +t9wcSk5wKv4U9UfXZ/Qto7mp1k0Zxk9KMlag333X3KdAmLx2MsN/GM7KB1dmaqgpWLYe3sp1k67j +iSue4LErsm/RwO7ju/nk50/YdnQbJQuVpHqp6pQrXo4CUoDtR7ez7eg2fj/yO1sOb2Hb0W3EFY2j +bpm6XFruUuqUqUOlmEpUKlmJ2CKxFJACFIwqSIEo8xtXNI4iBYsEVb783FPp3r07VapUYejQoRnG +rVGjBuPGjUu2gBwM4eqppJfhKlVtnNUMvdKppapb7OHtwBobXhY4rKpJIlITqAX8rqpHReSYiDTH +mNy/DxgZbDkC5fRpY7J+2DB47TVjc8qt8soZhi4dSovKLQISKGCMTT79tLlXgQqVexrew6cbPuXl +ZS/z4rUvBlHawNl+dDvXTryWZ1s/S5+mfbI1r0oxlXiq5VMBxU3SJHYd38XGgxv5Zf8v/HrwVxZu +W8juE7s5fvY4iUmJJGoiCUkJJCQlcPTMURpd2IiHmz1Mtwbd8pxCaaTw5ptvMmrUKA4cOECxYsVo +3749I0eOpESJEoElsGRJaMx/ZHYNMrA6mDXMXumkq6cC3ImZU1kF/AS097omR/RUzp5V3bhRddYs +1TffVO3WTbVUKdXbb1fdtCnLyTqywNq9a7XcsHK698TeTF135oxqhQqqa9cGfo1H/2XVnlWZLGXm +2X9yv9YeWVtHLh+Z7XllN2cTzurs32Zr8zHNteW4lrr18NbALoyPV92+XXXFinytp/LAAw+k8vzo +D39Oun7//Xc9fPiwqqoeOXJE27Ztq88884zPtFL95x9/bLwHLlkSFj2V2VmWYF6o6l2q2hCYAtyB +9ZuiqtOBjzDzOcUJwp9KZnrTe/bACy8Yy7cxMXDrrfD228Zs/dVXw4YN8MUXUKdO4Gk6giMxKZF/ +zPwHL7d9mQtKXJDxBV4ULgyPPWZ6lYFSsWRFXr/xdbpN78aJsycyWdrAOXnuJO0/bk/nSzvzaItH +sy2fnKJQgUK0r92eH3r+wF317qLF2BZ88vMn50eMj4cffjDKRDffbL6KW7UyToZyOTVq1GD48OE0 +bNiQmJgYevXqxf79+2nfvj2xsbG0a9eOY8eOJcefMWMG9evXJy4ujrZt27Jx48bkc6tXr6ZJkybE +xsbStWtXzpw5kyqvWbNmcfnll1O6dGlatWrF+vXrAy5j6dKlAUhMTCQqKipj8/fLl8Mtt8Dzz8P8 ++XCNX3OPgRGMRAp2AyoDc4FtQJwNq4fpvRQEqpPaTMuPQDO7Pwe40U/aeu21qsOHq65cqZqYeL6k +TkpS/eYb1S5dTE+kb1/VH380PRVH+Hn7x7e11YetNDEpnZsXAEeOqMbFqe7YkbnrHpzxoP7t079p +UjaYRjibcFbbTW6nPb/qmS3p5wb+t+d/Wntkbe3+ZXc9efSA6ttvG3MHJUqoXnaZsWM0fbrqgQPJ +15DLeyp5xZ3wxx9/rDExMRoVFaXdunXzWydAtWZN1XfeMV177/Bg3usBRTrf9tdxjHn6L4CaWc4c +PsN4j/QWKs8AA7zi/BdoAVwIbPAK7wq86ydtnTrVCIp69VTLl1d94AHVKVNUv/hCdfBg1YYNVevU +MUNcR4/6/f8dOcyuY7u07LCyumH/hqDSeeop1SeeyNw1p+NPa5P3m+jzi54PKu+0JCQm6D3T79Hb +Pr5N4xPjQ5p2buPE2RM69JX2ujMuWo/eeI3ql1+q2qGZ9AhIqJjBh+C3LFC9enX9+OOPk487deqk +Dz30UPLxqFGj9I477lBV1Zdeekm7dOmSfC4pKUkrV66sS5cu1WXLlmmlSpVSpd2yZctkodK3b199 +/vnU7a5u3bq6bNmy5HIE4qN+y5Yt2qhRI33jjTd8xgHStSkVrFAJdPjrTeBpjP+SykB/4GPgE+DD +ANNIhYh0AHaqatq+Xcj8qXTtCqNHm6Gr5cuhSRPjNGvsWKMB/8Yb8OuvZpgkNjYrtXBkF/3m9qNv +077UK1cvqHQefxwmTDDWowOlSMEizLl7Dp/88gkjvg+N7sqJsyfo8nkX9pzYwyd3fULBqMg2X11i +3hIGj1jJ1sEPU+u6Xxh54Q60VJDWk0MlVrJIKNwJ79mzJ0N3wiNGjCAuLo64uDhKly7Nrl27MuVO +GOCiiy7imWeeYdKkSf4jZsNqo0BbdgdVvczr+AMRWaOqA0TkWV8X+dFTeQ54FrghswXOKjVqwCOP +mM2Ru5mxaQbr963nozs/CjqtypWhQwezvPhZny31fMoXL8+CexfQdlJbdh3fxWvtXsuSIFBVvt76 +NX1n9+W6Gtfx0Z0fUbhg4Uynk6eYORN69YJZs7imeXOWH36Ev0/7O/O2zmN8x/GUK14u3CXMVipW +rMjPP/+cKszjThhI151wrVq1gBR3wgMHDgy6HPHx8RQLgxJdoE/JKRHpjFmxBXAX4Jld8in6VTVd +oSEi9THzJWut//nKwCq7XHg3UNUremUbthuokk64T7JL+dGRfZw8d5JH//so4zuOD1r3wUP//nDD +DfDkk1AkE0lWia3Cil4r6DqtK20ntuX9W9/323NSVQ6cOsDmQ5vZfHgzmw9tZuZvM4lPiued9u/Q +vnb7ENQml/Pzz8Z20ezZ0Lw5ABfFXcS3Pb5l8KLBXPzOxXRv1J2+TftyUdxFYS5s9tC5c2deffVV +Fi9eTOvWrXnzzTeT3QmrarI74b59+zJjxgxWrFiRrHfy4IMPcuedd3LdddfRvHlz/vrrL5YuXco1 +11xD8eLF/eY7btw4OnToQLly5diwYQOvvPIKPXv2zLC8oVZ+DFSo3I3RoB9tj38A7hGRokCmv/1V +9WfMHAkAIrINaKxGi34G8JGIvI4Z3qoFrFBVzayeSpuNc1MONs5lyXuZLakjp9n/135GR8fQdu88 +YF5I0qwPjCwOcy+HUlkY5nyGy9gXtYrZ45qwWMtSjPIIQhKJKIkkco4zHOGMHEEQimgcRShNPS1N +c72EGK2GTF7GEpaFpD65mQYbP2VBq9dZPb05TPc+UwjhVbrIwyxbNpJ3v29JrFbnwqSmRKv/l2Vu +IKvuhPfs2UOjRo2S3QkDTJ8+nV69evHcc8/Rvn17n+6Et2zZQtGiRWnVqhXX2FVZ/vL97rvvGDRo +EKdOnaJixYr07NmTJ554wm+9rnjumVTH97S4BQhOTyu3aNT/DjRV1cP2eCDQE4gHHlPVeTa8CTAB +KILRwPepgiwiurh32I0YOzJJlETRtGIzikUXDWm6R47A2rXBpZFIPIeTtvIXBwAhigIIBShANMWk +DMWkLIXI3+ZNjsbVYGPDLhnGS9R4tus37E1aTwJnmTt4ALnhXZSfEBFufOnfqcL+3uI6HmjXHM1u +d8IiUhkYBVxlg77BvOx3+b4qwAKIPAW8BpRV1cPWoOSvgGdh93K15u+tLbAJpAiVx/2kq66ROhx5 +g/xspiVcZJeZlkBXf40HZgAV7TbThgWFFVY3YPzPe5Nn/KmEi1COgeY2Irlu4OrniGwCFSrlVHW8 +qibYbQIQiiUcb2CWKqclT/hTCSeR/OBGct3A1c8R2QQqVA6JyD0iUsBu9wCHgsnYj54KQHURWSUi +i63fFMiCnorD4XA4cpZAV3/1wMypvIFZQvw98EBGF2VST8XTO9lDiPypOBwOhyNnyfLqLxF5XFXf +zOK19YEFGI+PHj2V3UBzVd2fJm6W/alkpWwOhyM8uIn6nMXf8uRsX/3lo0B/qGrVjGMGlJa3nkpa +fypLgQZq/KksB/ph9FRmAyNVda7vlB0OR16gaNGie8+cOZM5U9SOoChSpMi+06dPX5hxzMwRjAGi +UBqNUa/0rgaGisg5IAnorapH7bmHSb2k2AkUhyMCyI6XmyM85IqeisPhcDgiA7+rv0TkhIgcT2c7 +gdFXyXWIyE0islFEfhORAeEuT1YQkXEisk9E1nmFlRaReSKySUS+FpFYr3MDRWSziPwqIu3CU+rA +EJHKIrJIRH4RkfUi0s+GR0r9CovIjyKy2tbxXzY8IurnQUSi7ArNGfY4YuonIttFZK29hytsWCTV +L1ZEPrPl/UVEWoS0fsHYzc9tG0ZIbgGqAdEYv/cXh7tcWahHK6ARsM4r7FXg/+z+AOAVu38JPpya +5cYNY/Otkd0vAWwCLo6U+tkyF7O/BYDlGEsUEVM/W+4nMF5bZ0RS+7Rl/h0onSYskuo3Aehu9wsC +saGsX1bcCedmmgObVXWHqsZj/L10DHOZMo2qfguk9QDSEZho9yeSovjZAfhEjVLqdmAz5n/Ilajq +XlVdY/dPYkzyVCZC6gegqqfsbmHMh84RIqh+1hJGe2CsV3DE1A8zv5v23RgR9RORGKC1qo4HsOU+ +RgjrF2lCJa2Dr0hSkCyvqvvAvJiB8jbcl1OzXI+IVMf0yJYDF0RK/ezQ0GpgL7BEVTcQQfUjxRKG +94RsJNVPgfkislJEetmwSKlfDeCgiIy3w5cfiEgxQli/SBMq+Yk8vahfREpg/PM8ZnssaeuTZ+un +qkmqejmmB9ZaRNoQIfUTkVuAfba36W8FaJ6sn+UqVW2M6Y09LCKtiZD7hxnGagy8Y+v4F8aFe8jq +F2lCxZeDr0hgn4hcAMl20DxKopl2XhZuRKQgRqBMVtWvbHDE1M+Dqh4H5gBNiZz6XQV0EOOuYirQ +VkQmA3sjpH6o6p/29wDwJWa4J1Lu3y6Meayf7PE0jJAJWf0iTaisBGqJSDURKQR0xVhXzosIqb8E +Z5BiGud+4Cuv8K4iUkhEamCdmuVUIbPIh8AGVX3LKywi6iciZT0rZ8Q4sbsBM9EZEfVT1WdVtaqq +1sQ8X4tU9V6M5fIHbLQ8Wz8RKWZ70YhIcaAdsJ7IuX/7gJ0iUscGXQf8QijrF+6VCNmwsuEmzIqi +zcAz4S5PFuvwMcYszVngD6A7UBpj2mYTxiViKa/4AzGrMn4F2oW7/BnU7SogEbMybzWwyt6zuAip +XwNbp9XAWqC/DY+I+qWp6zWkrP6KiPph5hw8bXO95x0SKfWz5b0M8wG+BuOfMzaU9csVnh8dDofD +ERlE2vCXw+FwOMKIEyoOh8PhCBlOqDgcDocjZDih4nA4HI6Q4YSKw+FwOEKGEyoOh8PhCBlOqDgi +EhGJs6bLV4nInyKyy+6vFpFvsynP+iLyod0vLyIzRWSNNS8+Kzvy9Mq7moisz+K1Cz0Kfw5HsATj ++dHhyLWo6mHgcgAReR44qaqvZ3O2TwOj7P5QYJ6qjrJlqJ/NeUPW7TVNBf4BZPf/48gHuJ6KIz+Q +yvChGCdziMg1IrJERL4UkS0i8oqI3CMiK6yTpho2XlkR+VyM860fRaTleRkYs0BXaIpNpQoYO0sA +qOrPNl5xEVkgIj/ZPDrY8GrWCdJ46yjpIxG5QUS+s8dNbbwhIjJJRL634b3SFMVjJXmYLesaEXnQ +hl8oIkttj22diFxlL5mJMbnicASN66k48iPeX/QNMU7CjgLbgDGq2lyMR8pHgSeBt4DXVfV7EakC +fI1xXuTN5RgTFx7eAf4jIo8AC4HxagwVngZuV9WTIlIGY/bfY5/uIqCTqm4QkZ+Arqp6lRU8g4A7 +bLwGQAugJLA6naG1nsBRVW1hhd13IjIP6ATMVdV/i4gAxcDYgxKRMiJSXFX/yswf6XCkxQkVR35n +paruBxCRLRiBAcbuUxu7fz1Qz76IAUqISDFNccYFxtvon54DVZ1nezo3YUyor7JDYMeAf4vI1UAS +UFFEPL4rtqnxvQLGyN8Cr7JU88rrK1U9BxwSkUUYK7prvc63AxqIyN/scQxQG2Pv6UMRibZpeF+z +H2ONdqOf/8rhyBAnVBz5nbNe+0lex0mkPB8CtFDjTdQfqYbZVPUoxvvoJyIyE7ga84IvC1yuqkki +sg0okomyQOqelnD+XIoAj6rq/PMKaHyD3AJMEJERqjrFTzoOR6ZxcyqO/Ig/51LpMQ94LPlikcvS +ibMDM4/iiXOtNX2PiJQEamIsTscC+61AuZbUPZBAy9XRmiIvg7EUvDLN+a+Bh8T4rUFEaluT7lVt +3uMwroAbe11zAV5zQA5HVnE9FUd+xNcXua/wx4B3RGQtUABYBjyUJs4aoI7XcRPgbRGJx3y8jVHV +/4nIdmCmTesnjDnx9PL312tYBywBygBDVXWviHgLp7FAdcyQm2CGtm7HDOc9bct0ArgPQIxzpoNu +PsURCpzpe4cjRIjIeOA9Vf0xG/MYApwI5fJouzqshKq+Eao0HfkXN/zlcISOEUDvcBciC3QBxoS7 +EI7IwPVUHA6HwxEyXE/F4XA4HCHDCRWHw+FwhAwnVBwOh8MRMpxQcTgcDkfIcELF4XA4HCHDCRWH +w+FwhIz/B+FzXWb2SmNVAAAAAElFTkSuQmCC +" +> +</div> + +</div> + +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>Note that the trained model can be saved to a JSON file:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [8]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="n">gmm</span><span class="o">.</span><span class="n">writeFile</span><span class="p">(</span><span class="s2">"test_gmm.json"</span><span class="p">)</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<h2 id="Continuous-Gesture-Recognition-and-Following-with-the-Hierarchical-HMM">Continuous Gesture Recognition and Following with the Hierarchical HMM<a class="anchor-link" href="#Continuous-Gesture-Recognition-and-Following-with-the-Hierarchical-HMM">¶</a></h2><p>This example is inspired by the <code>test_hierarchicalhmm.y</code> file in the <code>python/examples</code>directory.</p> +<p>The data originates from the example patch: "hhmm_leapmotion_recognition.maxpat" of the Max implementation (see <a href="http://julesfrancoise.com/mubu-probabilistic-models/">http://julesfrancoise.com/mubu-probabilistic-models/</a>). +The data represents the XYZ Speed of the hand extracted from the leapmotion, rescaled (divided by 1000) and smoothed (moving average filter).</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [9]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># Create the training set</span> +<span class="n">training_set</span> <span class="o">=</span> <span class="n">xmm</span><span class="o">.</span><span class="n">TrainingSet</span><span class="p">()</span> +<span class="n">training_set</span><span class="o">.</span><span class="n">dimension</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># dimension of data in this example</span> +<span class="n">training_set</span><span class="o">.</span><span class="n">column_names</span><span class="o">.</span><span class="n">set</span><span class="p">([</span><span class="s1">'x'</span><span class="p">,</span> <span class="s1">'y'</span><span class="p">,</span> <span class="s1">'z'</span><span class="p">])</span> +<span class="c1"># Record data phrases</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span> + <span class="n">phrase</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/hhmm_test_data{}.txt'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> + <span class="n">training_set</span><span class="o">.</span><span class="n">addPhrase</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> + <span class="k">for</span> <span class="n">frame</span> <span class="ow">in</span> <span class="n">phrase</span><span class="p">:</span> + <span class="c1"># Append data frame to the phrase i</span> + <span class="n">training_set</span><span class="o">.</span><span class="n">getPhrase</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">record</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span> <span class="c1"># Create a single HMM (group of GMMs running in parallel for recognition)</span> + +<span class="c1"># Train the HMMs</span> +<span class="n">hhmm</span> <span class="o">=</span> <span class="n">xmm</span><span class="o">.</span><span class="n">HierarchicalHMM</span><span class="p">()</span> +<span class="n">hhmm</span><span class="o">.</span><span class="n">configuration</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span> <span class="c1"># <== try changing the number of hidden states</span> +<span class="n">hhmm</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="n">training_set</span><span class="p">)</span> +<span class="k">print</span> <span class="s2">"number of models"</span><span class="p">,</span> <span class="n">hhmm</span><span class="o">.</span><span class="n">size</span><span class="p">()</span> +</pre></div> + +</div> +</div> +</div> + +<div class="output_wrapper"> +<div class="output"> + + +<div class="output_area"><div class="prompt"></div> +<div class="output_subarea output_stream output_stdout output_text"> +<pre>number of models 3 +</pre> +</div> +</div> + +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>We consider a simple example of continuous recognition and folllowing with data originating from the concatenation of 3 recording, one from each class of gestures:</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [10]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># read test data (concatenation of 1 example of each of the 3 classes)</span> +<span class="n">test_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/hhmm_test_data1.txt'</span><span class="p">)</span> +<span class="n">test_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">test_data</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/hhmm_test_data2.txt'</span><span class="p">)))</span> +<span class="n">test_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">test_data</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">genfromtxt</span><span class="p">(</span><span class="s1">'data/hhmm_test_data3.txt'</span><span class="p">)))</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>As before, we initialize the performance mode with the <code>performance_init</code> function and we can then proceed to continuous recognition where we update at each time step the model with the incoming data frame. +In this example, we store the instantaneous likelihood as well as its normalized version and the log-likelihood. +We also keep track of the "progress" within the model, which gives an estimate of the temporal progression of the current gesture.</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [11]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># Initialize performance phase</span> +<span class="n">hhmm</span><span class="o">.</span><span class="n">reset</span><span class="p">()</span> +<span class="c1"># Create arrays for likelihoods</span> +<span class="n">instantaneous_likelihoods</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">hhmm</span><span class="o">.</span><span class="n">size</span><span class="p">()))</span> +<span class="n">normalized_likelihoods</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">hhmm</span><span class="o">.</span><span class="n">size</span><span class="p">()))</span> +<span class="n">log_likelihoods</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">hhmm</span><span class="o">.</span><span class="n">size</span><span class="p">()))</span> +<span class="n">progress</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span> +<span class="c1"># Performance: Play test data and record the likelihoods of the modes</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">test_data</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span> + <span class="n">hhmm</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:])</span> + <span class="n">log_likelihoods</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">hhmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">smoothed_log_likelihoods</span><span class="p">)</span> + <span class="n">instantaneous_likelihoods</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">hhmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">instant_likelihoods</span><span class="p">)</span> + <span class="n">normalized_likelihoods</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">hhmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">smoothed_normalized_likelihoods</span><span class="p">)</span> + <span class="n">progress</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">hhmm</span><span class="o">.</span><span class="n">models</span><span class="p">[</span><span class="n">hhmm</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">likeliest</span><span class="p">]</span><span class="o">.</span><span class="n">results</span><span class="o">.</span><span class="n">progress</span> + <span class="c1"># Note: you could extract alphas and time progression as for HMM, for each model. E.g. : </span> + <span class="c1"># print np.array(hhmm.models[hhmm.results_likeliest].alpha)</span> +</pre></div> + +</div> +</div> +</div> + +</div> +<div class="cell border-box-sizing text_cell rendered"> +<div class="prompt input_prompt"> +</div> +<div class="inner_cell"> +<div class="text_cell_render border-box-sizing rendered_html"> +<p>We can Finally plot the likelihood of each model over time, which is estimated causally with a forward algorithm (therefore allowing a use in real-time). +The last plot depicts the temporal progression within the likeliest model, which gives an idea of how the new performance of the gesture is followed in time.</p> + +</div> +</div> +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [12]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre><span class="c1"># Plot the likelihoods over time for the test phase</span> +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">411</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">instantaneous_likelihoods</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Instantaneous Likelihood of Each Model Over time"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Likelihood"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">((</span><span class="s2">"model 1"</span><span class="p">,</span> <span class="s2">"model 2"</span><span class="p">,</span> <span class="s2">"model 3"</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">412</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">normalized_likelihoods</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Normalized Smoothed Likelihood of Each Model Over time"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Normalized Likelihood"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">((</span><span class="s2">"model 1"</span><span class="p">,</span> <span class="s2">"model 2"</span><span class="p">,</span> <span class="s2">"model 3"</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">413</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">log_likelihoods</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Smoothed Log-Likelihood of Each Model Over time"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Log-Likelihood"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">((</span><span class="s2">"model 1"</span><span class="p">,</span> <span class="s2">"model 2"</span><span class="p">,</span> <span class="s2">"model 3"</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">414</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">progress</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Normalized progression with the likeliest model"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Time (Samples)"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Normalized Progress"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> + +</div> +</div> +</div> + +<div class="output_wrapper"> +<div class="output"> + + +<div class="output_area"><div class="prompt"></div> + + +<div class="output_png output_subarea "> +<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZUAAAEZCAYAAABfKbiYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz +AAALEgAACxIB0t1+/AAAIABJREFUeJzsnXd4VFXzxz8TQguQkJAAIYEk0lGKSBekKYiCiAqoFAv6 +2js2FIgdFUXEH6+KgBQBEXmVIkgNTemRLh0SCKEkQCChpMzvj3M32SzZZJMsBHS/z3OfvfeeNvfs +uXfOmZkzI6qKBx544IEHHrgDXkVNgAceeOCBB/8ceJiKBx544IEHboOHqXjggQceeOA2eJiKBx54 +4IEHboOHqXjggQceeOA2eJiKBx544IEHboOHqXhw1UJE3hSRb63zMBHJEJF8j1kRWSoij1rnD4rI +fLu0DBG5zn1UO6VhvIi8W8CyPUQkRkSSRKShu2lz0uZQEZl0JdrKhYa2IhLrYt4ipze/EJHfRKRf +UdPhbniYSi4Qkf0i0qGQdTwkIivcSNNQEZnorvqKGrkxC1X9SFX/Y3+rsO2p6hRVvd2ddV4BfAo8 +raq+qrrJMdHqvzMW07H9DnRDuy73jUVDvP3/KCLeInJMRNKvBA255RURPxH5r4gcEZGzIrJJRB4u +BF35Qk7vrareoarXFCN0Bd5FTcC/AMK18eEqShRl/0gRtu0qwoDtuaQr0EBV918hepzhJNAFmGtd +dwESgQpFRhEgIsWBxUA80Bw4DNwKTBCR8qr6hZvbK6aqhWGk1zQ8KxUXYVtxiMinIpIoIntF5Ha7 +9Iete0nW7wMiUgf4L9DSmkEmWnnvEJGNInJaRA6KyFC7emwz9/5W2jERGWSldQYGAb2t+qLt2t5u +tb1HRP5jV19bEYkVkZdF5KiIHLafoYlICREZbrV1RERGi0hJu/THRWS3iJwQkV9EJNiBTvuZqb2Y +qbqIRInIKesZphagz52KNETkXhHZJyL1rOsWIrJKRE6KSLSItHVSLqeV420issv6X7+yyysi8raI +HLBm4d+LiK9d+l0istUqt8T6v21pN4rIBus/ngaUyuU5c2qnnPXfnMG8p5tFZLezKnDCHEWkqYj8 +YfXLYREZJSLedunXi8gCEUmw/v837IqXFJEJ1rjaIiKNnT2DhUnAQ3bX/YEJDvQEi8ivVnu7ROQx +u7RS1rMnishWoGkOZWdY42mviDyXBz32dIQC96lqjKqmq+rvwPPAuyJSVkReE5GfHNobKSJfWOe+ +IvKdiMRZ79N7IiJW2kMislJEPheRE8BQh3qcvbf274t9HSetd66VmHc7xhoX/e3qzPW9LVKoqudw +cgD7gQ7W+UPABeBRzAv8JHDYSvMBTgM1rOtKQF27cssd6r0FuN46vwE4AtxlXYcBGcA3QAmgAXAe +qG2lDwUmOtTXBQi3ztsAyUAj67otkGqVK2blTQb8rPQRwC+AH1AG+BX4wErrABwHGgLFgS+BZXZ0 +pgNednQsBR61zqcAb1rnJYBWTvr4knrs0jKf1T4f8AiwC4iw0qoAJ4DO1nVH67pCDnRl+z+svp4F +lAOqAseATlbao1Y7YdZ//LMdPbWAs1YfFQNeBXZjVv/FgQOYj1Yx4F7gIvCukz5w2o4djRG5jNMM +4DonaY2BZpgxWw3YBjxvpZUF4oAXrf+oDNDUru9TgM5W2Q+BP3OhIR2oh1kN+ALlMeO6HpBul285 +MMrqo4ZWf7ez0oYByzBjMQTYAsRYaQKsB96y+jQc2APc5uy9sGtzKjA+h/vFMO/GbVbfnAXKWGle +Vt/Y+uN/wGjM5CAQWA08bjemUoGnrXIlcxvLTt6Xh6wx0t961veAWLu+ug1IAnzyem+L+ihyAq7m +g0uZyi67tNLWy1zR+hAkAj2AUg51XMJUcmhnBPCZdW77eAbbpa8BejkbnDnU9z/gOeu8LYaJ2H/8 +jwLNrPOz2H2wgJbAPuv8O2CYXVoZa+BXI2+mMgH4GgjJg9b8MJUM4BVgq0P/vAZMcCg7H+iXA105 +MZWWdtc/Aq9Z54uAJ+3SamEmFl7A28A0uzSxPgK3YBj7IQd6VuGcqeTUzkVbn5AL07BLP2WNwZPW +721O8r4A/Gyd3w9scJJvKLDA7roukJwLDenAdcC3wH+AJzATo+pYTAXDtFOxPozWvQ+Bcdb5Xnu6 +gcfJYirNgQMObb4BjM3rvQAWAh86STsCPGCdrwD6Wue3Abut80qYiV1Ju3L3A0vsxtSBnOrPaSw7 +eV8eAnbapd1g9Wmg3b0TGDEn5PLeFvXh0ankD/G2E1U9Z61+y6rqMRHpjZmtjhORlcBAVd2ZUyUi +0gwzK7sBM0MsAfzkkO2o3XkKZlaZI0SkCzAE8zHywjC8zXZZElQ1w7E+EQnCMMQN1rNglbddVAE2 +2D1zsogkYGaRcc7osfAq8D6wVozY73NVHZ9HGVcwEPNxPmJ3LwzoJSLdrGvBrBgWu1ins76uAhy0 +Szto1VvJMU1VVUQOYfomAyO3x6GsM+TWzpEcS1yKGzUHnYqI1AQ+B5pgxoU3Wf9pVcyH3Bni7c5T +gFIi4uUwljKbsn4nAR9Z56875AkGElU1xe7eQeAm67wKcMghzYZqQIg1lmzteWFWPnnhhNV2doJF +imFWHSesW1OAB4DJ1u8Uu7aLA0dsEi/riLGrziUrtTxgPw7PAajqCYd7rry3RQqPTsVNUNWFqtoJ +qAzsxMzYIGcl9BTM0jVEVctjZnSuDohs9YlICWAG8AkQpKr+wDwX6zuB+Vhcr6oB1lFeVf2s9DjM +B9vWVhmM0vUQZvUDZnDbUDmTSNVjqvofVQ3BiApHS+FNdxXoBAwWkXvs7sdiZoG2Z/BX1XKq+mkh +28v2/NZ5Gubld0wD85E+jGEEoQ5p1fLZTirZPzJ5wdn//V9gB1DdGmtv2eWNxawk3AZVXYH5gFdU +1VUOyXFAgDWObKhGFgM+gulDG+z7JBYzE7f/j/1UtRt5YxHQRURKO9y/D7MCWW1d/wS0E5EQjNTB +xlRirXwV7Nour6oN7B89DxrySs8P8npvixQepuIGiEhFS2nrg/kYnMXMVsF8GELFWKDYUBY4qaqp +1qrlQccqc2nuKBAuWVMU20rnhKpmWKuWTq7QrWbdPAb4wpr9ICIhImIrPxV4REQaWErAD4HVqhpr +zaAOA31FxMtSOGZ+oETkPuvlBCOaybDrE0cIZhZc0u7IqQ8EoxO4HfjKbmUyGegmIp0sWkqJMVCo +4ko/5IKpwEsiEi4iZYEPMCKvDGA6cKeItBdjOjsQ8+H5A/gTSBWR56y0ezB6jYK0U1iUA5JUNUWM +IcFTdmlzgMoi8ryl+C1rjUdncHXi0xXo7lhOVQ9h+ucj6z9uAAzArG7A9OmbIlJeREKBZ+3qWAuc +sRTqpUSkmBgjgyYu0DMJMxH6SYyBibelPB8JDFXVMxZ9JzA6nfEYBrbTuh8PLABGiDGgEBG5TkRu +cbE/4NL31hXkmNeF97ZI4WEqucPV2YcX8DLmI3sCI1e3vbxLMB/CeBE5Zt17BnhPRE5jZPM/5tGu +/fVPmMGWICLrVfUsRk7+kyUauB+jtHP1ud7AKDxXi8gpzMtTC0BVFwODgZnWs0VY9dvwOEafcQIj +c7efmTYF1ohIEmZV9ryqHsiFnjOY2dc567e9M7pVdTPQDfhWRDpbH6vuGAub4xixyUCyxndu/2Nu +fT0O80FajhETpWCU76jqLqAv8JXV5p1AN1VNU9VU4B6MQUEC0BOjfHcGp+24QL8tfZNk36fyuZU2 +EOhj/Q/fANMyC5mxcxtwF0bUtQtol0c7eaap6g5V3eGk3AOYcRSH6ZPBqrrUSnsHI1Laj9GJZe7r +sBhsV6CRlX4M82HNtMZzSpjqRYwJcSxGP3kaGI4xJPncIfsUjKHHDw73+2Mmb9sxOqufsFuZu4Bs +762NtLxIz+Xa6Xtb1BBLyXN5GxEZixkQR+2XjGJMAp/GiBTmquob1v03MRYxacALqrrAut8Y+B5j +gfGbqr542Yn3wAMPPPDAZVyplcp4jGliJkSkHWa2WV9V62NmDohIXaAXZubbBSOLty0D/wsMUNVa +QC1rCeuBBx544MFVgivCVFR1JcbU0R5PYcxV06w8NiuH7hh5cpolLtkNNBORykA5VV1n5ZsI3H3Z +iffAAw888MBlFKVOpRZwi4isFrOz1GZWGEJ287zD1r0Qspsb2sw3PfDAAw88uEpQlPtUvAF/VW0h +Ik0xiqzL7i3WAw888MCDy4eiZCqxGKsiVHWdiKSLSAXMysTepj/UuneY7Dbstvs5QkQuvwWCBx54 +4ME/EKpa4I2UV0T8ZVl/rQdq2t3+BeggIq+ISAbGvUkCxg/T82Icqu0B6gNrLVvxVOv+Lsyu3VxN +Z4vaXUFhjqFDhxY5Df9G2j30F/3hob9oj8LCpZWKiGwhF5tqzb6zNCdUs8qXFJEYjB+ccZj9GZ0w +GwZt+zps7Tjb/GZ/37Ma8cADDzy4iuCq+Kur9fuM9WvbAdvHlcKqepuIhAGzNfs+lQygFWZ18od1 +uzswUlU/tvLMw1h/HQSKqWoN6/79GOuv3118Bg888MADDy4zXGIqqnoQQERuU9Ub7ZLeEJGNmN2d ++YKI3AXEquoWB88FIRg3FzbYrL/S+BdZf7Vr165oCcjIgNRUKJn/EA1FTnshcVnpv3ABdu6EuDg4 +fx5KlYLQUKhdG4oXz7u8C/D0f9HiWqe/sMivol5E5Ga1HMWJSCsKoJexHLsNwriI8CAHFOnA3L8f +7roLdu+GpUuhZct8Fb/WX6rLRv/w4fDBB1ClCoSEQOnShrEcPGiYTNeucP/9cPvtUKJEgZvx9H/R +4lqnv7DIL1MZgHHt7ofRbZzEuFPJL6pjguxssnbLhwIbLWd2brH+AoiMjIT0dFi5knbdutHu5ZcL +QOq/DCdPQtu28Npr4OMD778Pc+fmXc6D3DFrFnz7LURHQ3j4penHjsHPPxvG8+ijcNttUL061Kxp +GE0BVozXEsLDwzl4MLfoAB64G2FhYRw4cICoqCiioqLcVm+BfH9ZTAVVPe1i/rEYp3VlVbW0de8T +jJuWCxirsLqqGiMmPOwijGt1wcSACFVVFZHN1rVi4hs8parznbSpqgoffgg//gixsXDgAPjm6X/u +340nnoBixWD0aEhJgcqVzcqlQpGGGb/20aYNvPwy9OiRd96DB2HZMjNely6FGjVgzJjLTmJRQkTc +Ynnkgetw1ufW/StjUiwifpb308XAYhH5zMZg8kA26y8ReQTjVfN6VW2Esf56ybG5nEgguwVY7qMw +PR2+/BKmToWbb4bZs10g9V+MVatgzhzDiMGsVNq3h989thCFwunT8Ndf0KWLa/nDwqB/fxgyBKZP +N5Oic+cuL40eeOAm5FcfMg7joryXdSRhnEXmClW9DeMKfauqVlPV8aq6SLPiRTyMicAGZkUzUlVr +WJZem8ny/VXMul8TeJO8fH9FR0NAANSrZ8QJK1bk83H/RVCFp5+GESOgfPms+82bw6ZNRUfXPwGr +V8NNNxmlfH4RFARVq8KuXe6nywMPLgPyy1Sqq+pQVd1nHe/gHtcqjwK/Wefu8/21fDl06GDOmzSB +9etzzf6vxqJF5rdnz+z3a9c21koeFBy7dpmJTUFRty7s2JF3Pg88uAqQX6ZyTkRa2y5E5GasWMoF +hYi8BaSq6tTC1JMjtmyBhg3NecOGsG2bMZX14FJMmwYPPwyOgenq1IG//y4Skv4x2L3b6EUKCg9j +/0fjkUceYciQIS7ljYiIYMmSJZeZosIhv9ZfTwET7Ky/EoGHCtq4iDwM3AF0sLvtzMor/9Zfv/8O +Xl5w+DDt2rWjXdmycPw4VKpUUJL/mVCFefNg0KBL02rUMArj1FS37aP412HPHrj11oKXr1TJI/7y +IE9ERUXx7rvvsnHjRgICAti3b5/L5dxp/ZUvpqKqfwENRcTXuk5ypZy99ZfdvfswoViPALNEpJdl +TTYLWCQij5Fl/bXWsv5KFZHd2Fl/5dZu5Nmz8OmnRq8CUK2asazxMJXs2LfPMN/rcpBklixpNuft +22dmzB7kH3Fxpg8LigoVICHBffR48I9EmTJlGDBgAA8++CAf2oxtXEC7du2y7a155513CkVHQa2/ +lgBLCmn99S3G6usMcAOw1KFM4a2/VMHfP+s6LAxiYlwg91+G5cuNyauj6MsGj/ilcDh+3CjcC4oK +FSAx0X30eJBvREREMHz4cBo0aICvry+PPfYYx44d44477sDPz49OnTpx+nTWDotZs2Zxww03EBAQ +QIcOHfjbToQcHR3NTTfdhJ+fH/fffz/nz5/P1tacOXO48cYb8ff3p3Xr1mzZssUlGps2bUqfPn2I +iIhwz0MXEEVm/QUcA+qoamPgJsDHyu4+66+wsOwfSttKxYPsWLECbrnFeXpYmNnn40H+oVp4phIQ +4FmpXAWYOXMmS5YsYefOncyePZsuXbowbNgwjh8/Tnp6Ol9++SUAu3bt4sEHH+TLL7/k+PHjdOnS +hW7dupGWlkZqaio9evTgoYceIjExkZ49e/Lzzz9nthEdHc2AAQMYM2YMiYmJPPHEE9x1112kpqYW +1WPnG0Vp/VVRVY8CqHFrX9G67z7rr2rVsl97Vio5Y906YzrsDIGBcOKE83QPnOP0aSNCLIg5sQ0e +8Rdg5ofuOAqK5557jsDAQIKDg2nTpg0tWrSgQYMGlChRgh49ehAdHQ3A9OnT6dq1Kx06dKBYsWIM +HDiQ8+fP88cff7B69WrS0tJ4/vnnKVasGPfeey9NmzbNbGPMmDE8+eSTNGnSBBGhX79+lCxZktWr +Vxe2+64Yitz6yw7u307rKMf2rFQuRVqaUSTXqeM8T1CQh6kUFMePQ8WKeefLDQEBHvEXZtHnjqOg +qGSniy1duvQl12fPngUgLi6OsLCwzDQRITQ0lMOHDxMXF0dISPa5sH3egwcP8tlnnxEQEEBAQAD+ +/v4cOnSIuLi4ghN+hZFf668ngYkO1l8PF7DtoyJSSVWPWqKtY9Z991l//f03REYCljLKs1K5FHv3 +GgeHPj7O8wQGwh9/OE/3wDlOnDD9Vxj4+UFysscC7xpBlSpV2Lp1a7Z7sbGxmczk0KFD2dJiYmKo +YZmcV61albfeeos333zzyhBL0Vt/baIA1l8WHANszQIeFhEv4AXAS0R+AD4BJonIrRjHk5WBv1X1 +tIicFpH/wwT2CgZyNXGI7NkTnnsu60Z8PDj8of96bN8O11+fex6P+KvgOH06u4eCgsDLyxicnDxZ ++FWPB5cdvXr14uOPP2bp0qW0adOGL774glKlStGqVStUleLFizNq1CieeuopZs2axdq1a+lgbdJ+ +/PHHueeee+jYsSPNmjUjOTmZZcuW0bZtW8qUKZNru6rKxYsXuXjxIhkZGVy4cAEvLy+K5zERKWrr +r5Ii8iDwLPCiiAwRkTx37YjIFEwQrlp21l/DMA4l3wG2ALUwTK4RxvvxjRhnk1MwSnmA4WR5RZ4O +PCqSi5TU8QW0WdF4NkBmYfv2vHd7BwYaMY4H+UdSknucmHqU9UUKx89Mbp+dWrVqMXnyZJ599lmC +goKYO3cus2fPxtvbm+LFizNz5kzGjx9PhQoV+Omnn7j33nszy950002MGTOGZ599loCAAGrVqsWE +CRNcanf58uWULl2arl27Ehsbi4+PD507dy7EUxcM+fJSLCLzgdPABiDddl9VPytQ4yL+mIBcLTFW +ZTOBLzH7V9raicaiVLWOiLxhmssWFTJSVdfkULfqkiXGIaI9AgLMRrLCiiT+KejTBzp3Ng4MnSE2 +1sRU8azy8o/vvoM//4SxYwtXT6tW8Mkn0Lp13nmvQXi8FF95XC4vxfnVqYSq6u0FbcwRqnpSRD4D +YoAUYIGqLrLpWqw88SJibxmWU1TInJGTqMCmdPYwFYM9e+CZZ3LPU6GC6TPVwpnP/BvhzpWKR1nv +wTWA/Fp//SEi9d3VuIhch3F5HwZUAcqISB8utQQr2BQmp53zHlFOdhw4AHltlvLxMTFWkpOvCEn/ +KLiLqXjMij24RuDSSkVEtmA+7N7AIyKyD6PvEIw4qkEB228CrFLVRKud/wGtyL9lWI6IHDUqc2ad +qYzymMdmISXFfPRccVtj67eyZfPO60EWkpJM6ODCwrOr3oPLhKKy/urqthazYycwWERKYZhUR2Ad +cBZjqvwxxmHlr1b+WcAPIjICI/aqAax1VnlkTlYMQUGelYoNBw+avTteLixYbRZgOYXC9cA5kpKM +6/rCwqaonzTJ1JmXyNIDD1yEu62/XGUqJ1U1SUQCCtWaA1R1k4hMB44CJYHzGJ9gvwHrReQ9jCuY +xlb+7SJyFMN0FBiq+dXuecRfWThwwHgZcAWefisY3Cn+io01+6727YOHHnK+ahwwwCj2BwwofLse +eJBPuKpTmWL9bgDWW78b7K4Lg+rAi6paChP9cRtmk+XHqloC+BR4GsCKX18J4yesNvBYribFOcEj +/srCgQOurzw8e1UKBnczlfh4Exp78uSc8yUkwLhxJiz01YZDh8xmWw/+0XCJqahqV+s3QlWvs35t +R4EjP1qbKNtYDiZR1TTL/X13wGacPYEsx5F3AdOsfAeA3UCzfDWag/grORleeQWaNoWvviro01yD +OHgwf0zFoyjOP9xp/bVpk/F+MHKkWbHktEhfv97suj9ypPBtuhPp6SYs8u1uMx714CqFq4r6xrml +q+pGEZlNLlZaqnpXDrcjgBMiMh5oiFn1vAi4x6Q4JziIcc6cMeM8NNSEXunTB2680UwG//E4cADu +yulvyQE2s2IP8gd3rlTi4sx+ocaNoUQJYw5es2b2fBs3mkH8v/8VvK2oKBgzxuhvXNG3uYJ16wxT +iY83m4/dVa8HVx1c1anktrlRMZEbh1vX92Bcq9jW5w9gdCbO2m8MPKOq6y0F/Bu4yaQ40vL7Bc6t +v2bOhHLlYOpUM86//BL69jWRh3Nzh3Ut4vvvTSj6SZMso7j8ir82bbp8xP1T4c6VCpjxK2KYy5o1 +WUwlKsroUfbtMx6nJ00quK+wt94yY2PkSHjppcLTDoauVq1MmIWYGI/Bhx0eeeQRqlatyrvvvptn +3oiICMaOHZvp1sUdKBLrL1Vt70KeZQAi8pmqNrFLmi0izvQuh4BYVbWl/4xhKu4xKbZjKplwEH/9 +/bdZldgmTvfeCz/8AN9+Cy++6KzmaxNffGH4wjPPmG+SR6dyBeAupmLbyGvzI1a/Ptg7LWzfHt5+ +2/yn991n8p06lf84LvHxxnXP99/D6NG5M5XRo6FrV2NBOHo09OgBwcFZ6ZMmwcqV8M03hpFUq2bC +U+/f72EqlwHDhw9nwoQJHDx4kKCgIJ566ikGDhyYZ7mi9v3lIyJvi8i31nVNEXE0Ny5jbWq0lYkA +cvSEZom4YkWktohsBL7DKOp/B1aIyE5gOTDfKjILeEFEdovIHqA+uZgU5wib+MuSR+/adWmU3CFD +jEeMc+5y6n8VIC3NrL5efx1mzcI83KlTULmyaxV4dCr5h6qRr5YrV/i6Spc2v0etRX/9+uaPPHfO +6CsA1q7NmijYHFDmF9u3Q6NGhjnkti9m61YzO7GJ2Z55Bl57LXueBQvM7Cw+PoupBAebaw8uCyZN +msSpU6eYN28eX331FdOnT7/iNORXsDkeuIjZoAhmlfC+Q56XgCgRiRKRZZgwwS/kUufzwEIgHPDD +eB529GjsiIL7CilTxogPUlIAM2lyDM3eqBG0aGFW62+9ZURjVwvsdbO//ALdumV9UwYPhuHDc857 +4oT5zrRpY3S5HDpklL6uyrYrVYLDuUYa8AD4I/YP/or/y1wkJ5vgXN759YbkBGXKZLkXsjkKfPRR +M1ABNm82/2u1agV365KYaPQ3eZW3hZDYtQts4XAdYxUlWU7MV60ylmuhoWYSEx9vVjiTJxu90J9/ +crXjWggnPHDgQBo1aoSXlxe1atWie/furFq1yj0dkB+oqssHsN76jba7tymHfCUxiveGQMk86gzF +MJV2wCzr3t8YZT1kub4HIxp73a7sPKC5k3rVKapVU92/X1VVw8NV9+27NMtff5mQPk8+qRoSovr+ ++6oXLzqv8kohIkL1wQfN+ZNPGhrXrDHXIuY6Pd1cV6um2qePOY+OVq1fXzU+XrV8edWMjdYNV3Hh +gqn87rvd9zD/MGRkZCiRaMhnIaqq+vzY+/RckL/7GjhzRvX8+azrgQOzYk/Vrm1+g4NNWufOqr/9 +prptm2pSkuqBA6pVqqju3Kl6+LDqn3/m3MY336g+9phqQoIZKM4wdqxqaKhq27aqu3ebwRcaatLW +rFHNyFBt00a1dWvVyEjVFi1UV65U/egj1ddeM7S2b6/64ouqRmfqli66XAgPD9eWLVvq8ePHNS4u +TitWrKiNGzfWTZs26YULF7RDhw767rvvqqrqzp07tUyZMrp48WJNS0vTTz75RGvUqKGpqal68eJF +DQsL05EjR2paWprOmDFDixcvroMHD1ZV1Y0bN2rFihV13bp1mpGRoRMnTtTw8HC9aH18wsPDdfHi +xS7RfOONN+o333zjNN1Zn1v388Ub7I/8TqEuikhpLMW5iFTH7ITPhIgUB54AbEHPo0TkG1V1FmR5 +BPAqZpViw+Wz/oIsEVh4OKdO5RzuomFDY6QiYsyN77zTnJ84YVYxPXq4rgNds8ZImlq2NOJ1Vdix +w3icT083Eoe6dY0h1vjxZvWxZIlxHDxqFCxcaPSbY8ealVVMjJnkHTgA1asb5Xv16kbKEhhoxFy1 +apl8M2aYckePmsVGpUom3+E95wi1iVRcQYkS5veXXzIdS3aY0IHPO39Oo8qNXK/HDTiUdAhvL28q +l3VRdHcFcOr8KTLUhFQ4c/EMF9Iu8PvGGbxR3JfgPMq6DMfNjlWqZJ1XqmSWoraVp7+/+dPvuAMG +DTImjXFxsHq1Wc289ZYZzMnJJtyxzVVPYqJZpfj5GdFderrx++aI+HjzImzYYFYhrVqZJfDZs8ZQ +YOtWI367/XbYudOITitUMCuV7dtNHSkpWascFyDvuMeZqQ4tmCtBWzhhgDZt2lCpUiUaNDAeqnr0 +6MGSJUt8qZw1AAAgAElEQVSA7OGEwawgvvzyS/744w9EJDOcMJBrOGGAfv368cEHH7B69WratGnj +Mq1Dhw5FVXnkkUcK9KyFQX6ZylCMfqOqFVDrZi6N/PhfoDgw2rruZ917zLEyEbkTOKqqf4lIu1za +dZ/1F2RagGVk5K5HtW2rrFEDPv7YMBJvbxgxwrw3trDR06aZj/oNN8CyZcZyMjjYvEdr1himdMwy +Nfj7b/Mut24NDz8MEyca8duzz8K8ecZIYN06WLzYiKsbNYK5c424/IsvjDTFz89IGvbuhQcfNFak +MTHGL2SDBoautDRDT+nShoajR7PUJ02awK5N+WQqAO+/b5TBhw9DaChLDyyl5diWxL4US6BPzl6f +E1IS2JO4h+ahzfPXlgMyNAMv8eJQ0iGqjqhK85DmrH7s6ojbPXPHTO6dfi/T7p1Gw0oNKVuiLEOW +DsHvAqSUdpPoKyfcequZeUycaAbGkiXG4gsMY1i3zpwfPZplZLFtW5Y4bs8ewxgeewx69TJpJ08a +hlSsmJl9nD4NS5fC3XebiVhwsGEE8fFw000we7bZExMSYtJtbS5caOpq2dKMG3umYtsAefx4vkR0 +BWUG7oI7wgl7eXnlGU544sSJjBo1CjCSpNTU1HyFE/7qq6+YPHkyK1euzDNAFxR95MeFlkK9BUav +8YKqOpoENVXVhnbXS0TEmS3qzcBdInIHUBooJyKTgPjLZv0FmRZgSUlm8pfTRMwRd99t3lcvL3j1 +Vfi//zMrhNtuM6bHPXsa/WhehhP2oeC//9787tsHH1oxLL/5xvwuWGB+t20zkz8w3wybAU10tGEk +3bsbnU9cnHnfGzaELVvMd6FWLfOur1ljFhe2d6BpU9i39hwd8stU3nrLcLsdOyA0lJLFStKjTg++ +WP0F73fIrlrrPLkzh5IO8UijR/hx24+se3yd02rTMtI4lnyMKuWqOM1z97S7OZFygt7X96Zrra6s +ilmFquYatKigeCfqHe6/4X5qB9bONd/249vx9vJm9SHD3EatHUWEfwSPNnqUAbMG8Ol1vYn/4zeq +u51CC/Xrw4QJZobx8stmINsGs7+/mW2AMfkLDzcRPrdty1rh2EzEU1KMMm7BAuPapbpFcUCAyX/f +fcaKa8MGc3/p0qyd/T4+ZqYUFGTK2WT4f/9tmErz5ub8wgVDU+XKZuXi62uYUUKCGdT/oDDfRRlO +eNy4cXzyySesWLGC4GDX1shFbf31rqomqOpcVZ0DJForFnukW2IxW5nrsAvo5YDRwB7gnHXsV9V+ +wAIul/UXZIq/nIm+nMHb2zCVzz4z79Jtt5n7t99u3m1n/8XQocZrxlNPZd1rYOfXOSPDrGQ6dzZ6 +TzDvd5065p2OizMK9tmzzfvXoIF5r318DBM5fNi8p1WqmLQtW7KYTPPmWSsVG1Np1gwO/n2uYBtx +KleGY8dIz0jnYvpFPr71Y8ZsHMNHKz4iQzOIPxvPyNUj+TP2T7Yf386vO3/lr/i/OH3+NGcvns2s +ZnfC7szzx2Y9RsjnIfy+53eemvMUqempnEvNbnoXczqGPw/9ydStU+nfoD9e4sXRZGMJte3YNlYf +Wk1qeirxZwtnWbTt2DYil0XywM8PZAYwWrp/aY55G37dkI4TO7IncQ99G/RlVewqwv3C6Va7G8de +PUbPyh057J1y+YNPRUVlKe5t8Pc38tFGjYzM9MQJaNvWDKgTJ8xsIzra5N2/P8vaY/duUxYMU7FZ +Dy1dmhXcLioqa+kbGmqYU2Bgdqaybx9cvGgGZVqaGeTe3qZMQoK5X6yYofGmmy5v/1xh9OrVi7lz +57J06VLS0tIYPnx4Zjjhli1bZoYTTktLY+bMmaxdm/UJe/zxx/n6668z7yUnJ/Pbb7+R7ELYiR9+ ++IG33nqLhQsXZlv9XGnk1/qrqoi8CSa0MPA/jKsUe7wKLLWz/loCvOKkvjTgZVW9HuPfK0JEbHP5 +y2P9BZnir/wyFXusXAnz55vJ2PTpRkQ1Y4YRX7Vta96tuDgjYYiMNDqZ963JfHS0WXXExUGHDmaV +U6MGvPGGSX/sMVOuY0fzDUhKgnbt4OefzV63hg2NqKxKFfOeXn89/P67ua5f3xgBxcWZaxtTiY/P +En/dcAMkHDrHmfR8rlTAcKajR0lOTcanuA9V/aoyr888JmyawK0Tb+WG0Tfw4u8vcubiGZpUacLK +mJWE+YXRcmxLqo2oxjNzn2Hp/qXUG12PfSf38U7UO6yLM6uYlxe8zNcbvqbi8Ir0mdmHfv/rx/k0 +I3OPTYqlQaUGrDm8hluvu5VaFWoxcdNEPl75MR0ndqTl2Ja8veRtgj8L5kLaBdYeNi9l428a8+EK +swz8bfdvTNw0MdfHW3N4DX0b9CUtI41x0eM4evYoHSZ2IOZ0DGsOrSHmdAwvzHuBqANRpGWkcSjp +EJuPbuaJm54AoH/DrAiaPmfPc6Zs8UIzugIhICBL6ZaSYlYzzZoZZmD7kG/YYJjCgQOG0YjA8uVZ +rvoDAoxuJDTUzFQSEw3zWrcua0BVq2bqCQw0g/iPP4yycMMGs7dGJHuwPNu+mbJlTdm9e68JpnIt +hBMePHgwiYmJNG3alHLlyuHr68vTTz9diKcuGPIr8H0U43r+TaA9ME9VR9hnUNXFIlIT4/ARYKeq +XiAHqGo8EG+dzxeRRRiRVmegtZ34KwpjqnwXMFKzhxNuBlwSThhy2VAcFAT79hWKqdSrlz20+x13 +ZJ0/+GDOZQICLnXXtHix+U1LMwzijTeMqO2774w3DjCTvIYNjbLfxlT27MlaKTVsaJTxPXuab36x +YkZn2qeP+aacO2cY2UMPmfzly0Pa2XNM+7U0bf7OLpLLEzamcjGZsiWM4rhxcGOWPLSER359hIRz +CXSt1ZX6FevjX8qf9XHraVm1JZM3GwcLo9eP5qftP5GWkcaAWQNYfnA5qkrtCrXZftwocE+dP8WK +mBWcSDlBm2ptWH5wOanpqXzf/XvGRo/Fv7Q/weWCeX3R6wCUKGaMCLafMOUnbJrAE3OeYM1ja4iO +j2bz0c282fpN7pxyJwB9G/Rly9EtpKSm0LJqSwDOXDhDuZLlOJR0iDC/MF5o/gL3Tr+Xqn5G2rpw +70J+3PYjzUKa8eXaL5n590yCfIKoXLYyW45toUmVJqQPScdL7OZpiYlIQAX2JO4huJzb1PWuwd/f +/PHlyxsl34YN8J//mE1Z0dFmkL37LnTqZAZhaqrRr/z5Z5b4y9/fzJ5atjQrmEqV4IEH4Pnnzcqm +cmXDSObONUylbFkzA2re3FicWMpmxozJ2jNjE8+lphqR3Pbt1wRT2bdvX7briROzT04GDBjAADuv +0N27d6d79+451tW4cWM22kSTOaBTp0506tTJJTpcTbuScGmlIiKNLf9fNwIjgd6YFcoyR79gdtZf +Q6zjceteXm2EA42A1ThYfwH21l+xdsVytf5yaqJtE38dOHXVRBW26U4/+sgwCTBMonhxs/KxeWUI +D8/yzGGj3eajr0MHMzFs2NB8J4KDzXXz5kYNYluplCwJpUnhXKnzmbocl1GxIhw7RnJqMmVKZO1p +rVKuCvP6zGPzk5uZ/cBsPuz4Ia/e/Crn3zpPdf/sWoXjKccJ9Q0l6kAUGZqBojQNMRYwwWXNx/dE +ilHVPTHnCX7Y8gMBpQO4MfhGvrrDePysXCbL8uti+kUql63Mwr0LaVKlCT9sMRLZX/7+Bb+SfoSV +D2NV7CpKe5fmOv/r2HZsG68teo1W41px9uJZZu6Yie8wX06knOBw0mFCfUNpUqUJpb1LM3Wr2aS0 +Lm4dG49sZNG+RYCxQAsvH8599e4jzC+MUt6lDEO5eNFweFVITKRkUDB7Evfks5PdAJsIy8/PDJrY +WGPJYcnuueUWwxgqVTJM58QJcw+yVhYBAUa22ry5YSoJCUZRV7KkUfT5+mbVV6FCFjOyWSnZLAa7 +dMk+06pc2QzMM2fM9Y03XpYu8KBoUFDfXyeBetZ9m+8vG1y2/rJBRMoCMzCK/7Mi4hbfX4MGRWJj ++JdYf82axd2z/FnyXNFalOSEUqWyVjT79pnJZtmyRpcZEmL0Or/8kjXB69YNPv88axNnu3bGiMC2 +J655c/jtt+wWqKXLHOR8gx+ZPf8bYmN9qGpv/pAbrM1ryReTKVM8u6MEL/GifqXs0aZLepek9/W9 +CfQJZP/J/aSkpjBh0wR+7vUzj/76KF/c/gU7ju+gSZUmeIkXg28ZzN7Evfx3/X8pU6IMU7ZMwUu8 +6F47+6zP0Zy4TmAdog5E0ateL15b9BqBPoHM2jmLOoF1aBHaghGrR1CzQk0aVGrAn4f+JPpINDUD +arJ432Imb56Ml3gxefNkDp05RLfa3QBoWbUl3//1PffVu4+5u+cCRjwWUi6Ew2cO07BSQ4a0HcLb +t7ydRci4cUZ5FhQEiYmUDa3KmkRHCfEVgM1XmJ+fWVIvWGA++jYTXlvgsMBAw1j27oXevY0lmU3E +YqujRg3DSHbsMPcaNjTWXbYZDBiZqo2R2eq2mTw6Yv9+Y8o8fLgZzK5EHvXgssHd1l8F3uDi7CDn +zZCX3LNL88Yo4l+wu7eD7Jsfd2jOmx/nk8vmx1q1M3Le9ZOUlLlp7P9eP5hzHjcgMjJS+/btq6qq +MTExWq5cOc3IcEJTAZHTZqjTp1Xnz8+6TkhQ3bDBgbbyfXVoW/TOV3/SgQPz0eCWLap16+qqmFXa +4rsWBaL5wIEDKiKalpaWa77U9FTtPKmzpqVfmm/EnyOUSPTl+S+rbyVf/eD7D/SLP7/Q1bGrlUj0 +ld9fUSLRh/73kC7cu1CJRHtO76lfrflKO03qpJU+raQlfUpq7297a92v6mrjLo212l3VtOaXNXXr +0a2qqjo+erwSic7cPlOJRDtO6KhEonf8cIeuObRGz1w4o1FRURpq2/Snqtf7+uqypk1Vu3XTyIgI +vbX59dpzes8C9ZOrsPVnum3Xq6rqkSNmjH/wgeqIEeZcVXXzZtWJE83mRNBzf/yhXStWVD/QXr16 +Za/4s89MuRUrzOZFUD1+XPXkSTOobLAf0wMGqCYnqzZooNqjh1OaRUT37t2beU0RbH5s166djh07 +1qW8jvRe7VixYoXWqVMn1zzO+pxCbn50VfzV1/p9OafDIXt+rL8AxgHbVXWk3b1ZZO1/cQwnfL+I +dBWRvRjdyyJrQ6atvQEishTgVLGdOFj2GZQrB8nJrK16Lw1Or8jr8QsFm2KtatWqJCUluWwCW5iZ +g6+v0acePnyY++67j9q1g+jY0Z8GDRpkyoJLF0/kfDFv0utNZdw4sx3BJYSHw/79JF84e8lKxRnt +ERERmRvDbBCRPPvC28ub+X3nU8zrUpvvztU781KLl/is82cElA6gRdUWvNDiBW6qchPT75vOoDaD +APjr679YOs5Yb91R8w5ahLZgwd4F1K9Un62xW1l6ein7Tu6jdoXaxJyKYXfibuK3GsV6t1pmxXJL +mBELlfIuxY5ndjD13qk0C2mWqVOyf46twcHc8sUXZsPSsWNkeAcRHbc51+d0B+xpiIqKMivK2283 +5oBPP51lXly/PvTrZ1YZqszYu5fjVatyMimJH3/8MXulgYG8A5Ro3x7f9evxBcpFRBBw3XVZqxjT +eNb5d98Zq8L167Msx/KgNy9ERkbi5eWVuXfDhpEjR+Ll5eWSd9/CIi9658yZQ/PmzSlbtixBQUH0 +69ePw1fQrZGXl1c2nUrr1q3ZsWPHFWs/Gy0u5rN9PcrlcDjGNHXZ+ktEbgb6AB1EJFpENorI7ZjY +9LdZJsUdgWFgwgkDPwEzgQyMS/3SwAcOVStA3ft+ZORIcoaPD+uKtSAsPmsDnV5u0898wB3L0X79 ++hEWFkZsbCwJCQlMmjQpc8NW6WKnKJbShLXHorit1/5LfAE6RdmyUK4caXGHsulU3E17XqgbVJfP +O39+yX1vL296Xt+TgNLmo+db0pdiXsXY9vQ2+jXoR4NKxpa7ToU61AiowbHkY1xIv0BJ75LcUPEG +qvtXZ8VyM9Go4FOBhNcSqOBTgZ3P7uS7u76jTmAdfEs62S2bnGxklE2aGCuK5GSWrQpm79GjbN53 +5SzAMvt/3jzjY6tECad6i4MHD1KrXj0kJ6eX990HXbtyf+/eJH3wAUk9enDmzBkSXdmwWLx4rj7P +8vOuiQi1a9e+RDk+ceJEajt6g71MyI3eGTNm0KdPH15++WUSEhLYtm0bJUqUoHXr1tn8gbkD6ek5 +z88vx36tgsLVyI/fWL/vOB6YGPL2eRcDNTGOIp8Daqtqjob+qrpKVYupaiNVvVFVG6vqfFVNVNVb +VbW2qnZS1VN2xZYAi1W1JmZvywLgCSuKZDZsLzOan+f8Rq1azfD396d58+b8aTmvO30a3o6ZytfL +p9K6dWvKlCnD/v37ad++PYMHD+bmm2+mXLlydO/enYSEBPr27Yufnx/Nmzcnxm6j1osvvki1atXw +8/OjadOmrFy5Msc+PHjwIF5eXmRkZLB69epMkz9fX19Kly7NdZZCRFUZNmwYX375JUFBQdx///2c +OpX1+JMmTSI8PJygoCA+zEPLvm7dOh566CFKlSqFl5cXDRs2pLO1n+FcxnE+XL2atolt+WV6Pb77 +LpB77vmatWvX07BhQwICAnjuuefs/yvef/99wsPDqXzqFCNeHU6ptFKZ6fYO9CZMmMDOnTsB6N+/ +PzExMXTr1g1fX1+GWx4vVZXJkycTFhZGxYoVsz2LrQ9q1KhRqD7IGJJB9QCzaK4XVI9iXsUoXqw4 +ia8l8kHHD/Dy8mJEsxHM72O2QfWo24Odz+7kwoULdOjQgRdffJGA0gFcvHiRbz/6lubXNyc4OJin +n36aCxcuNWhMW7WG0PMZ1LphJUc7PsgFbx/q3pCO32/laVQ7nOuvr5/N6ufvv/+mffv2+Pv7U79+ +fWbPnp2ZlpSURP/+/alYsSIRERF88EHWvCkjI4OBAwcSFBREjRo1mDt3bm7DwGk7kZGRvPvuu0yb +Ng1fX1/Gjx+fvaCPj2GQXl7GA/HMmZfUndv4z8jI4MMPP6RGjRqZ6faz94ULF1KrVi0C7Fc9TtCk +SRNSUlIyZ9/bt2/n/Pnz2VycgHFzUrNmTQIDA7n77rs5YhcBc+HChdStWxd/f3+ee+65SxjFuHHj +qFevHhUqVKBLly7Z3vPcMHDgQIYMGULv3r0pWbIkFStW5LvvvqNs2bKMGDGCixcv4u/vz3abexrg +xIkT+Pj4cMLydJCbE8mIiAg++eQTGjZsSNmyZcnIyMjWftu2bVHVTGeXP/30E8uWLaOqnaI0J4eY +gFOHmCLSQkRWichJa8Lf1qXOAKSws3MRiVHVag73WmG8DmdOVVQ19w0Crrd3L9BZVf8jIvuBqUBP +TJjhwSIyALP6af/KL6/w+QMjKHV9V0Jqt6NU0nZ2LppCl4EfEXO4DHvnf4J//G6GP3ArlcIqk+Yl +DJy8gONJKXzWrxN+pUvx5Ng5pKVnMLBrKxqFV+ajX1dQTLx4o3trABZs2UuLmiGUKVmCGau3M/WP +rfz44n0UL1aM76P+Iu7kGQbd3Zr4U2d5cNRMFr3dDy8R1LI9SM/I4JVJC6lftSID2t/IjDU7iNp+ +gHohgTzesTGjfl9H8vmLvH1PG/YfP8Wz4+Yx7MGO1KkSyJglG/ll7U6GPdiBGyMq2/o5s69e/2Ex +51PTubtpLa4PDaKiX9bKwveLaTRPzuA/T/yHxLaJLFu6kmPfHaNExbo07v4I/n7KktHv0Pbhp6hc +oxZ7Vq9k6+J53PbUy3TbsIbxUbO5GFiVj9u+SWzSUR6b8x4fdnyORpVq8+rCzzlyNoFJPd6juHjR +8+c3eKPVw9xUuTaqEH82gd7/G0TXGq15sen9xCTF88S8jxh359tU863MTzsWsyRmA++1+Q9+xcsw +cuN0ki+eY0irRzlwKo4nF33Kp7c8Q92AML7Z/Csz9yzj0zZP0bhibdtgy3zOj9b9QMXS5Xn0+jts +bgsz0zr87yUm3zaIKmUCGbZhChVLl+fe6rcwYOmn3FmtOQ/XMWZ1/7flF46kJPJGo/vxFi/ei/6B +iLKVeaxOF/46sYePNv3Ijx0GERC9mFuPr+a+x2fy05Q2+Kc8ziHv6Xw+9gte3P4WGTOqUep0Arc+ +8xalS8DsT96mZos21GvfmWP7drP0u1F0GzgE34qVWDH5O1LPn+eW/o9z/uwZFvz3c+p3vIOaLVrz +98oodixfROdnXqFY8ZIsHfd/HN2zk/6ff4t4eRE971du7GIMG9LT0/jlw8HUbNmG69t34ui+3Swd +8xVdBw7Gt2Il/po3izMJx2jdN8sc1t4sZtP8WZw5cZyb+z6a4/u4f8MaQurWp3ipUuxYvphti3+n +x5CPKObtzbYlv7N/w1raPvwE5YIqcjLuMKXL+1HSpww/vPwUIfXqc3PfR7l4LoVf3h3E77//nqMp +7TvvvMPevXupV68ep06dYtiwYbz++usEBASwdetWatasyZAhQ1iyZAm9e/dm0aJF1KtXj1deeYVN +mzaxbNkyTpw4wXXXXceECRO46667GDVqFK+++irffPMNjz76KL/++iuvvvoqc+bMoUaNGgwbNoy5 +c+dmevn18vJiz549mZM/G3bu3Em9evXYt2/fJRsOIyMjWbhwIatWrWLAgAFUqVKF9957D4DRo0cz +Z84cfvvtN6Kjo7n99tuZO3cuN910E5MnT2bIkCHs2rWL4sWLExERgb+/P3PmzKFChQqULFnykj7y +8vJi7969REREALBs2TL69euXyRgjIiIIDg5m1qxZpKam0qhRI44dO8amTZuoU6cOXbp0oV27dgwe +PNi26kkA+qjq7yLSEfgRs0DIO/5FYRQy1gcs1uF6EvAHxvprlHV8Wdh27Oq/F/jWOt+PcZU/GWOR +VgEYgFnNqOfwHJ7j2jk+/vjjHBXHkZGR2q9fP42JidGwsDBNTU3VatWq6aFDh7Rv3776zjvvqKrq +gAED9PXXX88sd/bsWS1RooQePHhQJ06cqC1btsxWb2hoaKaivkuXLjpu3LjMtPT0dPXx8dGYmBhV +da6oX7lypXp5eemFCxcuSfv666+1Vq1aqqq6aNEirV69embazTffrJMnT1ZV1aeeekqHDBmSrWzt +2rV1+fLlqmqMcb7//vsc+8YGR/qioqK0atWqmdfh4eE6ZcqUzOt77703r/9jgmb/7s4H+qkL32h3 +BIpWh+smwM2q+rSqPmcdz7uhHRsOA/YroyBgCzAHyHSYo6oCvA5MV1WxHcA0YJB1HgU85pAeBQyw +u34fGG93fSuw2+76VYy12inrSAc6WGmRwCTrPByjBypmV/ZJYDtQzu5eCnAawyRPWnWmAFWAr4FP +HOg9AnS0v5fTgWG43wOHcqHnENDW7noy8JZ1vgO4wy6tlFW+CsZk3JGu1cCD1vkBexqdtJ3Z7+7s +A+uZ33OSpkB1u3xHMW6DytrlqWjlO2l3nAaSrPR2mImVOD6r/f/v+NyYvV5rHegZBnwLVLLa9LFL +ux3YZZ3/7fBf1HbsT7s0p+3kRGMO5fNKz238pwDX59X31nWmQ0ZnqFq1KtWrV2fQoEHUqlXrEseM +jo4cy5QpQ0BAAIcPHyYuLi6bOMhWnw0HDx7khRdeICAggICAACpUqICI5Klst3ktthez2XDkyJHM +9Pbt23Pu3DnWrVvHwYMH2bRpE3fffTcAs2fP5qOPPsps29/fn0OHDmVzIhkaGgrkbPTiKhwdYIL5 +Tlr9/xiw0DofDfQSkUTrOInx0+jSDl6X9qmIyBkuZR5g3KU4+vrYijEDvrSX3YN1QA0RsY2e9sDn +mH0uG8m+pyYOs7KxRzVMHBYbcnoulyAibTAvVXs1RgSISCIuuJGxyr6DYcD2b1MM8KiqXhK5SESO +AHXsrn0wzCJPqGqiiAwH+ouIvytlHBAHhNldh2Hc7By10m5wyF8Vw6Qg/318WfrABXwL+APzROR2 +VU0BTpD1cXTnmI4ju3NUMGNzp9VmKqaPbdGdwshynnrEoaz9/5KfdgoFEWlN7uM/FqiOmTi5Bf37 +92fAgAF8b/PGaocqVapw0C5QWHJyMgkJCYSEhBAcHHyJjiQ2NmsfddWqVXn77bd54IEH8kVP7dq1 +CQ0N5aeffsoWuldV+fnnn7nnnnsAI57q1asXU6ZMoVKlSnTt2pUyZYw42sfHh9atW+fKLFxRxI8b +N46pU6dy/PhxvL29uXjxImfPnqWsY8iEvBELTFTVJ/JbEFxX1JdTVd8cjnKq6g0gIrNFZBYQCGwX +kd9FZJbtKAhxTmhJB57FKOhDgaWqukNV92Lkfvarot+AmiJyv4gUE5HeQF1gtmO9BURZzMufICIl +RGQIxiLOGQRARKpatPa36LbHN8CHIlLNyhskIndZaTOAriLSyvJS8C65MDARGSYi11vPXg7jX22P +qtrizObHZGQq8JKIhFubVT/A6LEygOnAnSLSXkS8RWQgcJ6s2DfxgEN8zVzbdlsfWPAWkZJ2h1MP +D6r6HOaDO1tESqmqAmOAL0QkyKInRERy9qORN2y0rgFSROQ1q8/aAV2BqVaf/gh8ICJlrQnUSxjR +Mpj+ft6iwx+zIncGp+0UkH57lCP38f8d8J6I1AAQkfoFnNBkonfv3ixYsICePXtekvbAAw8wfvx4 +Nm/ezIULFxg0aBAtWrSgWrVq3HnnnWzfvp1ffvmF9PR0Ro4cSbxdWOMnn3ySDz/8MFOZfvr0aWbM +mOESTZ9++invv/8+06ZN48KFC8THxzNgwADOnDnDiy++mI2+H3/8kSlTpvCgnYeBWrVqsXHjxgI5 +kbShcuXK1K5dm/Xr15OUlMSkSZNIS0vLZuCRD0wGuolIJxHxEpFSItJWRJy7EbeDO8RfNgzHrBIi +gbsxuo7P7A63QY2FWG0MR7V/Od4FfLBmxqqaiHmBBmJmfwOBO+0+qjnNoPMzq/7dOnZh9DspZHcj +49OkKN0AACAASURBVKzuDhixygwRSRKRMyJiM/cYidmXs0BETmP0U82s59kOPIN55jiMMi27H+3s +8ME4/TyJEetUxfhPc6THletxmI/acmCv9azPW3TtAvoCXwHHgTuBbqqaZpUdBgy2ltIv51C347U7 ++wDMRzfF7ljshAYb/mPV+YuIlMBsut0DrBaRU5gJTS0nZfMaP7axmQp0A+7AjM2vMDJr2/b75y1a +92H6fLKqjrfSxmDG3SZgPfCz08bybscV9LbGqW2sJolIIHmP/88xDND2P35HlmSjQBKCUqVK0aFD +h0xltf0MvmPHjrz33nvcc889hISEsH//fqZNmwaQ6bzx9ddfJzAwkL1799K6devMsnfffTdvvPEG +999/P+XLl6dBgwbMnz8/M11VGTNmTI7hhB9//HEiIiL49NNPCQwM5IYbbmDv3r2ULFmS6tWrZ4YT +btasGWXKlCE2NpahQ4dmhhMuW7Ysd955Z6YTyWrVqtGnTx9CQkJo3bo1qbYYObkgMjKS119/nerV +qzNjxoxM02Ob+3vHlU5uKx9VPQR0BwZh3ueDmG+na/xC3aRAd8cBjMWIUzbnkudLjN+xv4BGOaTf +jhEZ7MJu9/3VdOT0nBixywLMLPl3wM8u7U3rmXcAna4C+kMxxhDbMPqs56+VZ8CEul4DRFv0f3it +0O7wHF4Yca8tBPc1Qz9G77TJ+g/WWvf0asa1Ek54ypQp6uvrq15eXvqgLe64E2AY+2nMBMZt48ed +A2Wl9XsGs3fFdpzBKDVdqaM1xqlkjkwF6ALMtc6bA6sd0r0wM8owjP+xv4A67npGN/bVJc+J2fD5 +mnX+OjDMOq9nvXzeGEXvHixT8CKkvzIWQ8eIAHdi9BzXxDNgFOBgFOarMUrIa4J2u2d4CSOmsDGV +a4Z+zOrL3+Ge5glwz1EA5GQ99fTTT2dejxo1SntYbmnee+897d27d2ZaRkaGhoaG6rJly3T58uUa +EhKSre5WrVplMhVXLMFciVG/Z88ebdSokY4YMcJpHoup2HRubhs/bhN/qWpr69dR/1JOVZ1sQb6k +jpUYUY0zdAcmWnnXAH4iYu+NrhnGMuugmmX/NKvMVQUnz9kdsAVOmIARIYIRV01T1TRVPYCZMTS7 +EnQ6g6rGq+pf1vlZzAwmlGvkGdQo4MGsWrww/8U1QTuAiIRixFnf2d2+ZujH6JXy/+1xF1spINwR +TjguLi7PcMKfffZZrpZgrqB69eq88cYbl3ghyAF7VTUWN44ftzEVEQnI7XBTM3m5vndMP0QurvGv +MlRUN7j7v9KQyxCy4HLDUj5GYwwIotToaa4J2i2MwFhd2X8hryX6FVgoIutExKn38msVjlZokBVO +ODg4OMdwwjbYwgknJiaSmJjIyZMnOXv2LL179843HampqfjkHd11ivXrtvHjTkX9BozScEMOx3o3 +tvNvQcGnVFcI4hCygLwV/1cFVDVDVW/ErK7aWBZR1wTtInIncNRaKeZm9XZV0m/hZlVtjFltPWOZ +1/9jUFThhMeOHcvx48cB48Zm2LBh2aJKOsFP1q/7xn9usrGiODD6EGc6la+B3nbXf2O5yLeuWwDz +rXP1HJ7Dc3gOz1GgI9/hRtyuU7FBDPqKyGDrupqI5EeGKzifgc0C+lv1tgBO2ZZsFrJtjFRVtH9/ +9Nln0YyMrAe/cAH180Pj46lfX4mOLnpm6ngMHTr0stV97JgSGOhwf9QotGlTNDEx7zqio0moEcrD +vzx8xWm/mvs+/ItwdifsvjQtPR297jp0/vyrmv6r5bgm6X//fbRhQ3THjpzpnzQJDQ1F168velrz +OCw4hhspISIRQA1gLbkgvzHqXcFojMuIDsB7GOuvn4GmuRUCEJEpGLcXFUQkBhgKlABUVb9V1d9E +5A4R2QMkA4/Yl1fVdBGxbYyEo0fh119NKFV7u+wSJaB1a/jjD5KSehQ4Tv21Cm9vSEuzu3HhArz3 +nolB7O/C3rSgIEqdTKKYXBrn5N+M8PLh7D+5nxoB/8/eecdHUW0P/Ht30wOhhVAEErqAIEUQlEhT +FFQQsaKoiP4URbCgD0TF+hTEh6IPFcQuPvHJUxDBQkdEkd57TSiBBNJIsuX8/rizyybZlmRTIPv9 +fOazu3PrzM7MmXvPuec0y5+wfLkOcuMh7niQC4Bnn9UhlRMToWNHHarZbNwfixfDk0/CkiXQpk35 +9tN/nOFGlFKz0V4RLMAj4iJ53FEaQuVyEeloKEIRkTRjAZlPRGSIH3lG+khfCLRUSgk//AD9++ug +XAVp0gQOHCA9Xd/vlYlCQuXHH/XFfklBTyseiI0l/HQm5sAPdM9rGldvzIHTBwonLF+u46tUoJgX +QQKMUvDww/rFoVcvuPJKePppOH0axo6Fb789nwQK4hJuREReB173t2xpCBWLUsqMnpfDcG1h916k +lPj9dx2w3R3x8ciBg6Snu5c55U1PT/0OACEh+kXKybx5YPgo8ovwcKwRYVQ56z5gUGn2vSwobv8T +qidw8Mw5qx+r3UqIKQT+/BMeKDsjp8p6/isETZrQ85NP4MgR+PhjLWx++gk6+5youWAojVfNqWjX +IHFKqdeAlfgp5ZRS1ymldiildimlCvkzUkrVUkotUEptUEptVkrd57XCP/+Eyy93nxYfj23/QUJD +dZC6ikZp3lhmc4GRyrJlcPXVRaojp3o01dLz3Kad1w8Fit//OtF1OJF1AoD9afvpNL2TTti9Gy6+ +2EvJwFJZz39FoWfv3nDPPTB/vp4FqEQCBUphpCIiXyml1qLDACvgJhHxGSxZKWVC+yXqg17luUYp +9YOI7HDJNhLYICL9DN9DO5VSX8o5H1P52b8fWrVy32C9etiTj1W6qS8oMP11/Lgeorfw5MrKPdbQ +EMLKZ/xZYakdXdspVPam7eVY5jGw23WI4UaNfJSu3CQkJBRa2xGkdImPj+fAgQMBrzfgQkUpNVxE +ZnLOZTdKqTdEZKyPos7V8EYZx2p4V6FyDGhrfK8KnPIoUAAaNNBKeXdERyOZ2ZVSqJiM8andDqZ1 +66BTp3M7/cRuUoTYgzoCV+Ki45xCJSk9iay8LC20Y2IgOtpH6crNwYMH8aH/DRJgvDmVLAmlMf01 +WCl1l+OHUurf6EBavvBnNfwMoI1SKhntkG601xqbN/ecFh2NZGVVSH1KWeDUq2zbViwFot2kCCmS +5/wLn7joOFKy9eKzI+lHyLZkYz94IDhKCVKpKA1F/WBgrlLKjvYYfFpEhvso4y/jgI0i0ksp1RTt +6qGd5A9ydY6EBM81RUWhzlbOkQqc06uEbt9erDlfu0lhDk5/5aN21LnpryPpRxCEvGPJRMTF+SgZ +JMiFQ8CESgH/Xg8A3wO/Ay8ppWqKjm3ijYJhghtwLtKdgyvRwaEQkb1Kqf1o77hu3cC8uHMnvPgi +oJV/+RSAUVGYcrKJLBi3spLg1Kvs3g133eUzf0HsJkWIBEcqrlSPqM5Zy1lyrbkcydD+nfJOHiOi +ZqBc3wUJEniWLl3K0qVLA1ZfIEcqa9FmxMrl83pjEwpH/iuI62r4o8AdQMHYntvRMeJ/N7wTt0C7 +0XbLi3ffDcM9DJKiozHnZmPE+ql0OIXKoUPg4iXVX4JCpTBKKWpH1yYlO4Uj6YZQOXFML4oLEsQD +w4YNo2HDhrz88ss+8zZu3JiZM2fSu3fvgLVf8IX7pZdeKlF9gXR931hEmhT4dGy+BAqSP0zwVrS7 +5e1KqYeUUv9nZHsduEwptRH4Fe3/3/MIqL6X6JehoWC3ExXqO6rahUhICNjybJCcDBcV3WltUKi4 +p3ZUbVKytFCpHVUb28kUCI5UgpQBS5cupXfv3lSvXp0mTXw+ckuNQE5/9RaRxUopt6voRGSOrzoc +q+EL7PvQ5ftJdGhU//AmVJTCGh5NFVM2UM3vKi8UzGawJx/TD7xiDNfsJjAHFfWFiIuO49CZQ6Tn +ptO+bntkSwo08dNTQZAgJSA6Oprhw4czZMgQ/vnPf5ZbPwJp/dXD+LzRzXZDANvxHx8KUmtYlCFU +Kh8hIZRo/YRdBU2K3VE7ujZrktfQMKYhVcKqQGpqcKRyAdC4cWMmT57sNkZ9tWrV6Nu3L2fOnHHm +nzt3Lpdccgk1a9Z0xqh3sH79ejp16uSMUZ+Tk5OvrR9//JEOHTpQo0YNunfvzubNm/3qY+fOnbnr +rrto3LhxYA66mARy+muC8Tms4AbM96cOXyvqjTw9lVLrlVJblFJLvFYYG+s12RIaRbSqxELlcAmE +iknH4g2Sn7ioOJYfXE7L2JZUCauCOpPun5POIBWeOXPmsHjxYnbu3Mm8efPo168fb7zxBikpKdhs +NqZOnQrArl27GDJkCFOnTiUlJYV+/fpx4403YrVasVgsDBo0iHvvvZfU1FRuvfVWvvvuO2cb69ev +Z/jw4cyYMYPU1FQeeughBgwYgMVy/kzTl5VHwCm+MrisqL8WaAPcqZS6uECeasC/gRtE5BLgVq+V ++vC/YgmNporyHfzmQiQkBMxHSjZSCZoUF6Z17dasOLSClrVaEh0ajcrMrJjO5c5DlArMVlwee+wx +YmNjqVevHomJiXTt2pV27doRFhbGoEGDWL9+PQCzZ8/mhhtuoHfv3pjNZsaMGUNOTg6rVq1i9erV +WK1WRo0ahdlsZvDgwXR2MemfMWMGDz/8MJdddhlKKYYOHUp4eDirV68u6ekrM8pKqPjzV/oTX34I +8J2IJIFTx1Js8kKjiKLyjlRMSYehYcNilbeZCE5/ueHyBtrXXNcGXakSVgVT1lmoUqWce3VhIBKY +rbicTzHqy5OyEir+/JX+rKhvAdRUSi0x4lsPLUmn8syRRHK2JFWct5jNYE4+rF3ZFAObSWEOetUo +RJvabfjsps+4tfWtRIdGY84+G3TRUsmoKDHqy4tAWn9txr3wUEAdN/uLQwjQER0ALBr4Qyn1h4js +cZf5RWPhI7hZ/AhYVRjhpvNnrjKQhISA+eQxqFu3WOXtJjAHTYoLYTaZuefSewCoElaFkOyc4Eil +knHbbbcxceJElixZQmJiIm+//bYzRr2IOGPUjxgxgrlz5/LXX3851508+OCD3HzzzfTp04cuXbqQ +lZXFsmXL6NGjB9E+Xk5EhLy8PPLy8rDb7eTm5mIymQj1oQaoyIsfS2rh5c+K+iPASRHJAXKUUsuB +SwGfQsUdFhVGhMm9+/YLnZAQCDl+vNhCxaaCinpfRIdFE3Y2LyhULgAKOl/05oyxRYsWfPnll4wc +OZLk5GTat2/PvHnzCAnRj9s5c+bwwAMP8Nxzz9G/f38GDx7sLNupUydmzJjByJEj2bNnD5GRkXTv +3p0ePXr4bHf58uX06tXLmScqKooePXqwePFir8cW6MWPqqJ4BjUCe+1Eu74/io6DfKer23xDcf8u +2qdYOPAncLuIbHNTn6+ol2xqPpiDVw7hxk8He813IXL55bBqUzTmE8eKpUhe070J6TdcQ5+xH/rO +XEl59493eLT7E5jyLOdCywZxi1Iq6KW4jPF0zo39xZ6GKA2HksWiQHx5EzDTsaKeczHqdyilfgY2 +ATZgujuB4i95KowwKudIpQqZWmtZzLdou5KgTsUH1SUcS6iZ8KBACVKJqDBCBXyvqDd+TwYmB6K9 +PMIIU5VTqNS2H8dSow7mYtpY2oJein0SYzFxNsJMJXUvF6SSUlbWXxUSC5V3pFLbfpzcGsW3n7Ap +MNmDQxVvVLOaORteqW+xIJWQsrD+AkBE2vlRx3XA25yb/proIV9nYBVan+LTp5gncgkjSiqnUIm1 +HiO3egmEiglCgzLFK1VyISssKFSCVC5Kw/rrUePzC+PTr2Adfsaod+R7A/i5pB3Ok8o7UqllPU5O +9eJZfoFh/RWc/vJKFQtkBue+glQyAiZUXGLLXyMiHVySxiql1gGBiFEP8BjwX6Do4QoLkEM4oZV0 +pFLTcpycmJJMfwUV9b6IzhVOBodzQSoZpTE2V0qpK11+XOFnOz5X1Cul6gM3icj7+Of6xSu59rBK +LVSySyRUwBR8XnolMsdGRmhwOBekclEa1l/DgY8N548Ap4H7A1T324Cr92KvgsXXivpcCSPUnt/t +dGUhyp5BXnhMsctbTcHpL19E5to4E2Ir724ECeKViryiHgARWQtc6hAqInLGRxEH/qyovwz4j9JL +RmOBfkopi4jMdVehrxX1Z21hhEq6n927sAiTPCymsGKXtynBFBQqXgnPsXA6xFre3QhSwQmGE/aB +UqqOUmomOhzwGaVUa6WUh0Dx+XDGqFdKhaFj1OcTFkaY4iYi0hitV3nEk0DxhyxL5VXUh0geFlV8 +LbI9aFLsk5DsHLLCFHm2ynmNBSlbJk+eTNu2bYmJiaFp06ZMnhyQ5XxFpjR0Kp+iLbMcsXx3AY/7 +KuRnjPp8RUra0SxrGKGVVKiEk0u2tfgjFasCc9Cthntyc7W3gsxMciPDyMqrnDF7gpQ9X3zxBadP +n2bBggW89957zJ49u8z7UBpCJVZEZgN2ABGxol2q+EREFopISxFpLiJvGPs+FJHpbvLeX5I1KgBZ +eWGE2iunUKkelceuAyWd/goKlUKkpkJEBEyfDpmZWKPCyczLLO9eBSkh50M44TFjxtC+fXtMJhMt +WrRg4MCB/P7774E5AUWgNIRKllKqFsZIQinVFfBLr+IrnLBSaohSaqOxrVRKtS1JRzPzwgippNZf +4WFprN1X/Ied1SRBRb07Nm3Sn6tWGUIlgixLcKRyIXC+hRNesWIFbdq0Cdjx+0tpWH89hdaFNFVK +/Q7UxlfYX/xe/LgPuMrQ1VwHzAC6FrejmXlhhFTSkUrG2UPsi1lMRsZNxYp2aw2OVNyzeTNcdhms +Xw9t2mCPigyOVAKEeikw8XtkQvGuW0c4YYDExETq1KlDu3baUcigQYOcLuZdwwmDHkFMnTqVVatW +oZRyhhMGvIYTBhg6dCivvfYaq1evJjEx0e++TpgwARFh2LBhxTrWklAq1l9KqR5ox5AK2GmEB/aF +z8WPIuIaqHk1hSND+o3FAjkShslaOYWKyWolIv4wa9ZAcQxJrMF1Ku7ZvRtuuglefRUaNMBaJzqo +UwkQxRUGgSIQ4YRNJpPPcMKff/457777LqADb1ksliKFE37vvff48ssvWblypc8AXaVBaVh/7QUe +EJGtIrJFRCxKqR/9KOpPOGFXHgAWeKvQmx45OxtM4WGo3Fw/unbhYbZYsdc5xOrVvvO6I6hT8UBy +MjRvrkMK7N6NPaYqGXkZ5d2rIGVIeYYT/vjjj5k0aRKLFy+mXr16JT+YYlAaOhUL0Esp9YlhGgwl +GFG4QynVCxhG/oWQhTh82HNadjbYwyPhbCWNUW+xcTryAH/8UbzyViWYgtZfhUlOhvr1IT4e9u4l +rGZtTmafLO9eBSlDbrvtNubPn8+SJUuwWq1MnjzZGU64W7duznDCVquVOXPm8NdffznLPvjgg3zw +wQfOfVlZWfz0009kZfke7X711VeMHz+eX3/9Nd/op6wpDZ1KtojcrpR6BlihlLoV/8x//Vn8iFKq +HTAduE5E0rxV+I9/vEhLIzpLwQU+2dlgjYqBjMr5FhlitXGKVPb/nYrdXhNTEV8vrEow2YJCpRCu +QmXtWiJr1eVE1ony7lWQEnI+hBN+/vnnSU1NpXPnzogISinuvvtupk2b5vXYAr2iHhEJ6Aasd/l+ +NVoncsKPcmZ0rPl4IAzYALQqkKcRsBvo6kd98vLL4pGNG0VubL5dpEULz5kuYE5WNUvCuEhpeMUq +Wb++6OUnD6orxx8aGviOnc/Y7SLh4SLZ2SJPPCEC8vaCF2XMz2PKu2cVHv0oClKWeDrnxv5iy4DS +mP56wUVg/QZci7bq8or4t/jxeaAmME0ptV4p9ZeH6gDYuNFzWnY22KJjIL1yumkJtQoX17+UhC6b +Kc5LitUU1KkUIjUVoqIgMlKPVJSiWlxDTmQHRypBKg+BDNJ1sWjz3ySlVMcCyf4o6n2GExaRB4EH +/e3T+o029ACoMCdOQERcDOyunNNfoVY7XRKu5HfbWhYvgsd9+jzITx42zEGhkh/H1BdooVK1KnFV +g9NfQSoXgdSpPIV+4L/lJk2AwHlA85Pks3tJT29BjBtnvAcPQp0m0fDbWbDZwOxe+FyohNrgyma9 ++e7gOI4sh7Q0qFHD//Lp1iwizMVfkX9BUkCo5EVV49brLqLOiEPeywUJcgERsOkvYxSBiPRys/kl +UHytqDfyTFVK7VZKbVBKtfdWX9Oeq/j1V/dpBw9CfILSpp8VUFnvSXH22WefFWkRlFtsNkwCDUzx +bH1sE4n9k/jmG/+LW+1Wsu25RODeBj5QSr9Zs2Zx3XXXOX+bTCb27dtX5HqGDRvGCy/oWdmVK1fS +qlUrZ1rjxo2di9YcFLf/9iPJ/Lq1Po8+CtLuUt7v8x2RWS05mL6PFya8wNChQ4tV76pVq2jRogUx +MTHMnevbf2ogzn9ArrMScvDgQUwmE3a7b9cNFaG/RWXEiBG89tpr5d2NgBMwoaKUutnb5kd5x4r6 +a4E2wJ1KqYsL5OkHNBWR5sBDwAfe6qzabjGffeY+7cABPUNBjHsLsJUrV3LllVdSvXp1YmNjSUxM +ZO3atb4OI2AsXbrU403lzQLEH2w5Z8kzQVRYNEopLrr6v0ybpgdsrrh74AKcyj5FeFgUysPNXtSH +midhMWTIEBYuXOj8XdLjBujevTvbt2/3mqe4D+XDqw6zK7M+S5fCjJkmvtjRme++icCUEc+W/SeL +3f8XXniBUaNGkZ6ezoABAwqlJyQkEBUVRUxMDFWrVuXaa691rtguCUXpb0JCAhEREaSmpubb36FD +B0wmU761GKXVB2958/LyGDduHPHx8URHR9OyZcsy9eLrTui9//77jB8/vsz6UFYEUlF/o5ftBi/l +HDhX1Itege9YUe/KQOBzABH5E6imlPIYvnCHfR5/bTnJb7/l32+3w8qV0KULWqicye+aLCMjgxtv +vJHRo0eTlpZGUlISEyZMIDy8bAOOi2EWKAFeD3I2+wy5IfomVCgWnplCrbpZ/MPrqp9zpGSnEBVR +tbAUKib+PjgCfR4CTfqy9cRdcynffQfPPQdbt0LnztC1bk+WbNqJHy/cbjl48CCtW7f2mK6UYv78 ++aSnp5ORkcG4ceOcfqjKCqUUjRs35uuvv3bu27JlC2fPng3Iy0BJueWWW1iyZAkLFy4kIyODL774 +gunTpzN69OiAt2Vzc1847uXKQCBj1JfUyYy7FfVdfORJMvYdd1fh/R3u5+fHBjJo/FNcN68RnS6N +JDoKtu+AKo0VOVUhvVlDcr6aQeaAa53lNu/YjdisdGoQzb4/fgIgIUog/QB7Vh1gzk+L+Gbuz7Rr +3YI583+jRvUY3hg/mgOHk5n60SwsVitPj7iXm67Ts36ZWdm8POVDVvy5nsjIcG694RoeGnoLoC+2 +Dz7/L/+d/yu5eRYSu3Rg/OMPkHJwO1d01T6BYqpWQSnFjLeeJ+lQMlmnUxh250DmzF9MTNVoxj8+ +nO6Xd3C2Nem9z1j553pMJhMDr+vBI/ffhlIKu93OlA++4ocFS6iRB0/Pnw/ANU2uYc2gHsz+aTTL +BjWj3zWRNKhvJivHwu9bDpEZoT3lKJOgFGxJXcemvXaabpxN2nf/o1PrTrz8yAvE1YwDYMOydTRt +0ISTp09xY4/r2X1oDzf1HsgtV5+zxzcO3nkO9v+2B1vdXAyDRgD+t/h7vv3tO7567QtnkX0Ld5FX +5yxrt6/j6XeeYdKo1+nc+jL2HtnHax+/wdZ926hVrSaP3fYo13btC8Dp/WlEZoSz7ZvN/L1tDf94 +71kWT/sFAEtWHgs/ns+IYSM4dvIoV156JQ3rNGDrrI0gwn+XzOHjHz8lPSuDDi3b8/x9zxJXPRYR +2LB7IxO/mszBY4eIr9uIN/Yf5ZJ33uLii+HTTw/w8MP3Ua/eelq3b0N66AZ+WN6BFz5cQ6P64dSo +FkpoiAmlQCn4+YfZfPflTLIyztD60k6MHPsiNWvVZvjgvhw/mkT//tdjMpv55tfVhITkn3Y8m2th +9bZDnI3aCcDuIyf56U/9/WjSYd59/Xn2796BMpno0OVKHnlmAlHRVQA4eeIY0//1Gls3rkVE6HHN +9Tz01HNs3HuUU+nZDL57OL/M/Y4qMTE8/NQLdOrmfoopO9dC4rU38c6/P6RRx6sB+OS9KXTp1Z/d +u9/ht7V7iT2STXZWJh/+6xXWr15JeGQk19w4mFvveRgAu93OM888w2effUa1atV48skn87WRnp7O +k08+yU8//YTZbOa+++7j5Zdf9vmwXrRoEb/99ht79uyhvqHz6tKlC19++SVXXHEFo0eP5u+//+bN +N99kzZo1znJTpkxh2bJlfP/99+Tl5fHss8/y7bffkpeXx6BBg5gyZQrh4eEsW7aMu+++m8cee4wp +U6bQt29fPnOZItmxYwcjRozAarVStWpVQkNDSU1NzRecy1HHqFGjePPNNwkNDeXf//434eHhjB49 +mtTUVMaMGcPYsWOd98zEiRP56KOPOHPmDH369OGDDz6gevXqXs9FmVASe2RPG3A98AzavPgF4AU/ +ygwGprv8vhuYWiDPPOAKl9+/AR091CfBLbgFt/Nne//996VVq1aSlJQkaWlp0qtXLzGZTGKz2URE +5KabbpIRI0bI2bNnJSUlRS6//HKZPn26iIh8+umnkpiY6HbdxdixY6Vnz55u0+Lj42X69OmSnZ0t +MTExsmfPHmda586dZfbs2SIi8vjjj8vAgQPl9OnTkpmZKQMGDJBnn31WRESWLl0qISEhMm7cOMnL +y5OcnJxC7bjr33333SfPP/98vjpeffVVsVqtMmPGDImNjZUhQ4ZIVlaWbN26VSIjI+XAgQMiIvL2 +229Lt27dJDk5WfLy8uThhx+WO++80+0xesLbfyElef57TYSbvW0eynyAnqI6DEwANgMzfXZEhFJ/ +4gAAIABJREFUexte6PJ7LPAPN3Xf7vJ7B1CnJCfAS39aAh8Dh4A84AegtpF2L9pRpiPvJeiYMbEu ++04C7dBTjLlAS5e0/wMWyznB+LBLWgujPROQYNRrckm/F9jl8jsSHbsmzthygHCX9DuARcb3RcD/ +uaRdU7D+AudgP9Dbzf6PgDdcfkcbx9gIGAr8XiD/IeB+L+faDjRxs/9eYHmBfGONfrVy2X8bsMzN +tfK88f0T4GXjew/gUIFjvNPl90Rgmh/HeTewukCbq4B7gIbGfxjpkvYV8LmH43fXTh7QyNv/UOAY +0oFUIM34HO4h70BgrfG9G3qUX+j/93Cd2YA4b9cK8CzwT7Ru9Ge0Tb/dOGce7wVAevfuLR9++KE4 ++OWXX5xC5dixYxIeHp7vgf31119Lr169RMS7UHnggQc8PnC7du0q//znP0VE5O6775ZXXnlFRER2 +7dolMTExzvaio6Nl3759znKrVq2Sxo0bi4gWCOHh4ZKXl+e2DU/9cwiV++67T+655x6JiooSu90u +IiIZGRmilJI1a9Y483fq1Eni4uJk0aJF0qpVK1m8eLEzLTk5WUJDQ50C2B8oofDwtPma/rrR+IwD +rjD+fIBexg3kLkjWFSLSTim1SUReUkq9hQ/HjwbOcMLAUfTD8M4CeeYCjwLfGHFaTouI26mvkiIi +O4H7AZRSLdAPhbeBu4wsru2eNcqcLLCvChCLnmZ01VQe5Jw/tPrGb9e0EKAO+q3BHcdc+nnWGP5X +AWoBocBRY58yNkfb9ck/fZjf653/1AecVgsikqWUSkUfU8E2QE9lAqCU2oL2miBAPxEpahSh0eiH +s6u2PR7oavQB9DGbMfRvfuD6X2YDDk98vo6z4Pk76JKWJiJnC6Q18NC+u3ZOGXX5q+EeKCJLCu5U +SsUB7wCJ6GvEjBY6GP05KCKetD0FrzNl1OFt4c2XwHKgMYXPv9d7ITk5mYYNGzoTXP1XHTp0CIvF +4nSS6HiANWrk6tnJPbGxsezZs8dt2tGjR53u7IcMGcKYMWN47rnnmDVrFjfddBPh4eGkpKSQnZ1N +p06dnOXsdrtDKAJQu3btEnsErlWrlnMqLzIyEoC4uDhnemRkpNNo5+DBgwwaNAiT4V9JRJx6rbS0 +NKKioujfvz9Tp06lSpUqJepXUfGqqBeRYaJ1JaFAaxEZLCKD0dZZns6g40bKVkrVRzuY9OkuU/xY +US8iPwH7lVJ7gA+BR3weYQAQkV3oMMmXFKP4SfQ5iHfZF885v2bJbtIs6AedJ6HiicPokUotEakp +IjVEpLqItDPSj6Lfol3bKg75+qyUikYLtCQ3bYDLw1RELhGRqiISUwyBIujYPIOUUq7mTYeBpcYx +O447RkRGFrH+gng7zmT0SNKVRpw7BzWUUpEF0orazhGPJQrjSbHwT/RIoY2IVEePsBx5DwONDMvL +gCAih9Cjln4Ufun0ei/Uq1ePwy5eYF09/TZs2JCIiAhOnTrl9N57+vRpNjmConnh6quv5s8//yQp +Kb8rwT///JMjR444455cc801pKSksHHjRv7zn/8wZMgQQAulqKgotm7d6vQefPr06XyRHn3pdQKt +pG/UqBELFizI5814x44dbNiwgfT0dHbs2MHBgwfLxWTZ34upoYgcdfl9HM83yY9KqerAm8A64ADw +tYe8+RA/wgmLyEgRaSYil4rIOj/7XySUUi2VUk8qpS4yfjdEj5q8+fR1e9UYb4GzgdeUUlWMkdgT +gEP7/DXwhFIqQSlVBXgNLVDtQAr6gdDUn36LyDG0UJ6ilKqqNE2UUlcZWWYDo5RSFymlauDDy7NB +mFIq3GUzG30eppRqp5QKRz+4VhsPlPnAJUqpAUops1JqJHrU5YvwAu24uzYV+gHcxziOh439PwIt +lFJ3K6VClFKhSqnLlFIt3dRRFLwd509Ac6XUHcZx3g60AuYZ6X8DLxl96c65UX9R2vHiZ9tvqgKZ +QIZxPT/tkvYXWgC+oZSKMs77FQFo8370dF0+F+C+7oXbbruNqVOnkpSURFpaGhMnTnSWrVu3Ln37 +9uWJJ54gIyMDEWHfvn0sX77cZ2f69OlDnz59GDx4MNu2bcNut7N69WqGDh3KI488QtOm+vYKCQnh +1ltv5emnnyYtLY1rrrkG0ALBbDbTr18/WrduTUxMDHfeeSezZ8+mf//+9O/fn5SUFK/hhPPy8jhy +5AgWi8UZTvirr77iu+++cxtOuFOnTogIgwcPdhtO+KGHHuLZZ591mmqnpKSwefNmahgrmG02GyaT +qXzc3/szR4ZeP/IzcJ+xLQDe9aNcOFCtNObtvLR5HVrXsosCOpki1FEf+Ab9ppiBfqObBlSRc/PN +rnP9TQFbgToOYRgVANXRN84J9HD/b7Rg3oR+UD5ntJGLDr28yHHegBfRDwUb+g3wTde2jTw2DJ0E ++iEyzagvDT2tcpuRZkZ7PDgJ7AVG4FunYjM2u/H5MnrkscPorxWtN6sP1EALtcNAltH+e8DvaBPx +3cB2oK+b/hds534359n1OBOM/t1v/G6OFi4n0ML4N6CdkeaqU7na6Pd69Ig4Da0LcPT9JPrN2XH+ +/w84ZbSdAdzh0p8rjP8yDT19280lLQE9DZSOvnem4kGn4tLOHqP9uUB9l7R9FNCpoF8I1xl59xvn +22r00wr8YORrjb6ObehZhA/Ir1NqAPzPaPcE8La7a7zg+XfT/0J9dLnmbJzTD1VHX88WtN7osLFf +rFarPPnkk1KrVi1p0qSJTJs2LZ+iPj09XUaMGCENGjSQ6tWrS8eOHeWbb74REe86FRGR3NxcGTt2 +rDRs2FCioqKkefPmMmnSpEL5VqxYISaTSR577LF8++Pj4+Wiiy6ShIQEiYmJEbPZLA0aNJCNGzfK +r7/+KuHh4fKy4cF2586dEh0dLYsWLRKr1SqTJk2Spk2byvXXXy81a9YUk8kk77zzjtx7771yyy23 +SGhoqNxzzz3SsGFDWbduncTFxcnq1avFZDLJv/71L0lISJC8vDxJTEyU2NhYWbRokdjtdpkyZYq0 +bNlSYmJipFmzZjJ+/HiZNWuWxMTEiMlkkiFDhng8H6JPuqCfN6Ncrv+dxvXqfG4D4zzdu26vBV8Z +XCoeBEwxtkFe8pmBAUZHn3RsXvLPxHjAuuwr1gEaN5rD03Eo2tPxxf4eY1ltQHegfYFjngg8Y3z/ +B4bi1ngorEfPRScYx6fKuf91gfbG9yrG/3Sxu2NAC83jxn9WIY4BiHK5VlcDV55P59/o1xNo/cXc +8/D62QfUKLBPfAKB2YpBQkKCzJo1y/l78ODB8sgjjzh/v/vuuzJo0CAREXnllVfk9ttvd6bZ7XZp +0KCBLFu2TJYvXy4XXXRRvrqvuOIKpxXYiBEj5IUXXsiX3rJlS1m+fLmzH4sWLfLZ3z179kj79u1l +ypQpHvMYQiUZPV0dsOunKHOpq9CK+kXoN09PzEOPZmqh35odmyc+QVuKuDIW+E1EWhptjgNQSrVG +W/q0Qs/ZTlP5Jyv9WUBZ7ojISvTbrSsDAYdx+2fATcb3AejpMKuIHEA/nAuu3ylTROSYiGwwvmei +BXwDjGNQSvVFz6cPAsYDEcAnFeUYRCTb+BqOfhFJ4zw6/0qpBkB/tNWYg/Om/+gXjaLrcQIlVopJ +IMIJJycn+wwn/NZbb1GzZk1q1qxJjRo1OHLkSJHCCQM0bdqUsWPH8vnnPm1V9oqeZg3Y9ePX4kel +1G3oaZel6AviXaXU0yLyXzfZG8g5xbBPRGSlMbfqykC06SfoA1yKFjTOAwQOKKUcB/inkdefBZQV +lTgxLNlE5JhhtQP6mFx1OY4FnxUCpVQCetS1Gm3efVwp1Q2YhQ5TcD2wEK1bc1Cux2Doa9aipy0/ +EJFtSqk659H5n4LWjVRz2Xc+9V+AX5VSNuBDEfnIV4Hzifr167Nly5Z8+xzhhAG34YSbNWsGnAsn +PG7cuBL3w2KxEBUV5SvbLOMzYNePv28L44HOInKviNyDflA/7yHvz8abaknI94BFmzSD5xX1FyLF +f6UqIwzDgv8Co40Ri2Me4yURiUWb1XbDuwlqmSMidhHpgB5dJSqlelL4fFfI86+Uuh44bowUvZkU +Vcj+G1wpIh3Ro61HlVLnlydIH5RXOOGZM2eSkpICwLZt23jjjTfyRZX0wLfGZ+Cuf29zY44N2Fzg +t6ngPpe0m9G2/mfRSsoMIN1H/fHk1y+kFkg/ZXy+Cwxx2f8RLoswcVlASTmtCg5uwS24BbcLYNtu +PEfzLUJHzzpcHgidykKl1M9KqfuUUvehzUZ/8pD3LfTDPUr0WoGqIuImoolXjivDUaRSqi7n3nST +gIbKcJGPNvN1davvuoCy3BSRgdgmTJhQ7n2ojH0P9r/8t2D/y3cz+MH4nAvcoZQKU0o1BpqhTdE9 +4pdQEZGn0YsN2xnbdBHxtMbhMLBFXHrnB46V3w7mopX9oE0b8x0g2kz1AbSNfXdluMiX/AsogwQJ +EiRI8XCsE9yGXlu0DT2QeMTXs70oXop/R9uWC94l1T5gqVJqAXo9AEbn/uUus1JqFtATqKWUOoT2 +F/YG8K1S6n70uo7bjDq2KaX+QAuaGegV9R3Riv0dRp6FQEulVFGEWpAgQYIEMRCR0y7fXwde97ds +aVh/7Te2MGPziogM8ZB0tYf9i4AQEfk/o29xeLDw+vm+x6kSGk7VkDCiwiMJj44hJDoKc2Q49rAI +0mwxnLDUYG+VS7G48TrjzrOCv/uKWt6x3/GZm9sThzWgyaT3m0wgouPB2O1gtZIvRkfBOjx92shD +pf1B1IbZRIgiyhxOVGgYUeZQokPDqBYZTlSVMCKiTYSGmXSoZZNJbyEhUK8eGa2aMj/9b7It2bii +UJy96CyfrP+kkGsKVUCv7JpeMM0fwsxhCILdxXWVQmE2mQkxhRBiCiHXmkueLQ+zyYxZ6f1mkxm7 +2Mmx5jjzm5QJs9IhpSVe+HLTlxRtsA2WPWmotYdQmTlYzSGIKYTq6VlUsdqpEhJFtfAoakZGEhMd +QWSEIjSswB9f8EIo5veeWVnw8ccQGakvEovl3P/neiE5vtvtEBp6Lm9enk4zm/UWEnLue2amLusO +Rz5HWzYb5OToeh0Xriuu14fLcfTMzIQZMzym+ypfonRfecPD9bGkpenjE0HsdpJPneHIiTQsFhvV +D+1n0fBRKBHMyoRZmQhRCrMyEWY2Uff+odTp3JYLFX9HKg7rrxMASqna6BXL+YSK4cKjqoiMCWgv +i8m0hTOxKRs2ZaVZjNCmio1wi4kIawiReWaq55qokx1G+yxY1O4Zfm33JHaTFi7u7ht/9xW1vGN/ +/s+eJCWdS3cIEtfnQmio/ixcNv/nmdCd7Ir+kPhT80g8kESHozl0SYIlCfU5E6Y4pSxYlAWrOQ+r +yYLdlIvJHoLJEkaINQyzPYwQeyhhEkoEoTSyZNL86DGs/Zuxcmj3c8eC0WgcHD+Y38+nM8153OIx +zR9EhDxbHkopTMqEQiHoOWG72LHarVjsFsLN4YSHhGOz27DardhEf5qUiYiQCGd+m9iw2XVwpfAq +4ezZsweTPy6xBKouOMaDc9YRn5nJ5to1yQwPI9xmJ8Ru43h0GMmhgsWci8V8Fqv5LHaTDWWJxGSJ +RNkiCbFHECqRhBFJqCmCSFMkEeYIIkMiiQwNJzo0nPBwExFhQrVqQkxVUBS4cFwupJ4isGIFZGfr +B31YWP6LyHEhuX63WM7ldThGtFr1g9NmO/e9SpVzF13+P+RcPrtdfw8J0Q9hx4XqKgRdb4YCF21P +gD//9Jjuq3yppQOcPQtKITVrsutEMhuSdpHOUQSFyR6NKDPRmNh3xIQosGPXLz7Kjig7NmWjequW +3FuBhMrSpUsDFgIcjJWRPjMptVlE2rr8NgEbXfe5pP0h2ozUV523oF2QtEILrHUuaePQbjqsaHPV +X4z9HdHze/WAGSLyuFJqLCAiMrFA/YWm/kSEHGsOGXkZpOemk3Y2jV/2/sKP8ybz3apG1DdXg3nz +oFo1LgS2pWzjH7/9gzNrV/Hl/AhibWHITTcReWUPTJ27gBGwqCAiQmZeJqdzznAi/QzJp85wLO0M +x8+c4eDxM+zeZeLovGasPXwrVXauAz88xV6IiMB7ff7HnSsfIfWVaTR/8kZUqO/3tBxrDiezT5J8 ++iQHU1I4nJpC8ukUjmee5ERWCqlnU0jLO0m6NYVMSSGHNELt1QjJrY01PZaQU+25ucEI3niqDRdd +IAb1CQkJ+RxIBil94uPjOXDgQKH9SkebLb4HTD+tAd6ksO+viR7yvo9WqA/FS+wVdLyS5ugV8x1d +9rfCg1sA9CLHy419i9EL6zbgElvDpR7xly3Ht0j9SXXl4F03ivToIWKx+F22ImK32+WtVW9J7KRY +mfv6MLHHxop88IFIEWIt+OLMGZFZUfdL0lNvBazO840ZLxySNHMtyV65tlTbsdqskpKVIttObJOl ++5fK6O9ekcgJsVK1x3RxCalxXlOU+zVIYPB0zo39xbYe82ukAqCUGoz2kQSwQkT+5yHfJ+5ll9zv +If8S4CkxRioFRx6Gwv9FtMJ+sYi0Vkpdhw6gFYX2UfOGm3rF32MDWLJ/CXf/dwgHFrYktN8NMKZC +zOAVGbvYeWT+I6w+spqlSddQ/bNvYM4cuOyygLc167bv6fDXh7Q64E+4nAuLjAz4rdbt9Hi4FTWn +vljm7e9N3ctlH1wBXyxkw8IOuHj6OC8x3o7LuxuVCk/nvKQjFb+FSmnhRqi8C/whIrOM3x+hTdkO +Aq+LSF9jf3e0A7QBHuotklABePjHh2mYksf4p+fC0qXQpo1nLXwFRER49KdH2XR8E7+dvJ6IT7+A +JUugjj+e54vO5sUpJFzTjKp5qVpBW4n49NUjDH7lUqqmHoLo6HLpw/tr3uetH3+kV/J8Zswoly4E +jKBQKXtKS6j4tU5FKXWzUmq3UuqMUipdKZWhlEr3kLeBUup/SqkTSqk8o8x2pdQmpdRm49NbbIly +46WeL/HWie9J+8do6NMHrrgCjh3zXbACICI8/evT/J38N79UGUHEe+/Dzz+XmkABuKRXbVJVLY4s +dR9V70Lm+Iffk9lrQLkJFIBhHYZxOuovvv31AIf8jQ8ZJEgp46/11yTgRskfwtUTn6CdlN1q/L4b +uEtErvGzrSTyRw5sYOzztN8jL774ovN7z5496dmzp9eG61Spwz2X3sPr5gwmHT0K48bBQw/BDz94 +LVcR+Hj9xyzYs4Dfu39C1NU3wPz50LCh74IlQCk4EduG3J+20qBPSeNhnT8cOwbtjy0kbuLQcu1H +REgEN7UayI7BP/D556N57rly7U6QYjJs2DAaNmzIyy+/7DNv48aNmTlzpjNaZSAItPWXv4r63/1V +0gAb/Nw3Ce0yPQO99iTG2N8a7eN/N1ohn8S5abpNxv5d6LUw13nphy89lVv2p+2XmhNrSkZuhkhu +rkjduiJbthSrrrJiy/EtEjspVrYd+FukbVuR998vs7ZX9RwrP17+cpm1VxH44qMcyQqpKnLyZHl3 +Rb7b9p1c/m5fad5cxG4v794Un+LerxcC9913nzOeii+8xVNZsmSJ9OrVS6pVqyaNGzf2WZenc04J +FfVep7+Maa+bgb+VUt8ope507DP2u+OUEdbVbGx3oyPnFSQTHeApBG3Rtb5g8+665LIBxVjg4IOE +6glcFX8VszbP0jb799wD//lPoJsJGDnWHO747g4mXj2RVpM+hksu0aOrMqJ+jxbkbtubz5T/Qmf/ +f/4ks8HFUKtWeXeFq5tczdaMVajwTP7wFuw6yAVPdHQ0w4cPZ/LkyeXaD186lRuNLQbtebivy74b +PJS5H+1W5RjaN9ctwLCCmUTkZRFpKCKR6CmyVUbSAOAd0XHom6FHJ10Mx5JmY39zdOCumwrWGwge +uewR/r3m33rEM2AA/PhjaTQTEF5d/irNazZnWFKcnvKaNq1MjQsaJcbTwHbgfJghDBhq3VpCr6gY +YXpiwmO4tM6lJN75J5995jt/kOLRuHFjJk+eTLt27YiJieGBBx7gxIkT9O/fn2rVqtG3b1+vMep3 +7NjhTHPEqK9WrRp33HGH2xj1HTp0oEaNGnTv3t1tjHp3dO7cmbvuuovGjRsH5qCLS0mGOYHa0Ota +7jS+u3VvD3QCfnHZ3x0jlKqHOn0O/zxhs9uk+dTmsvLgSj0FFh0tcvp0sesrLTYc3SC1J9WWY3s3 +idSrJ7JsWdl3Yu9eOVs3XmrVEpkyRSQ7u+y7UJakpIj8J/Rusc2YWd5dcfLkwiflmXn/lFq19OV6 +PlKS+7UsSEhIkG7duklKSookJydLXFycdOzYUTZu3Ci5ubnSu3dvrzHqmzVrJhaLRfLy8iQ+Pl7e +eecdsVqt8t///ldCQ0Od01+OGPVr1qwRu90un3/+uTNGvaMfvsIJ//bbb+U6/eVVUa+UekZEJhlm +voUmOERklEveF9xUcQ96igu0+3pl1DNeROYZ5cYDFhH52g8ZWCSKqqh3YFImRlw2gml/T+PKm7/S +azxWr4ZrC0Y9Ll/GLRrHhB4TqPP0i3DvvXDVVWXfiQYNiEg9yoq/rfxjfAiTJ+vZwu7dfRc9H1mz +Bi4PW4fpsqfKuytOLm9wObM2z6J1a1i4UA+ugwSexx57jNjYWAASExOpU6cO7drpILeDBg1i8eLF +AMyePZsbbrjBqUwfM2YMU6dOZdWqVSilsFqtjBqlH52DBw+mc+fOzjZmzJjBww8/zGXGurKhQ4fy +2muvsXr1ahITSyeWWaAV9b6svxzWXn/7UZe70GSfA8OBWiJS1zVBKfUyenV+TeBPpVQDETmCVswP +VUq9hHbTkon2SJwENFdKbULHPN+DXrviEVehUlTua38fLy9/mRNZJ4jr0AE2bKhQQmVN0ho2n9jM +DxHDYOtW+Oqr8ulIWBjUqUOrqkeYOzeBhQvh5pth/XouGBcirmz4PYs+ufuhdevy7oqTLhd1YfTC +0UwYIsyapS5YoRKoWd3i6v8CEaPeZDL5jFH/+eef8+677xp9FSwWS5Fj1BeFgi/cL730Uonq86pT +cYwmROQzd1uBvG85NmA6EInWpfwHaOKm+nVoy6944Hu0y3uArej49O2AB4FLgb9EhxWORQcBawlc +ho5BXyrUiKzB4FaDmbluJrRvD5s2lVZTxeKV5a/w/KWjCH38SZg+HSIiyq8zCQlg+BC67jp49FF4 +5JHy605pkrpiK1kNL9bCtIIQXy0em91G937JLFigV/tfiIgEZitt6tevX8iPmSNGfb169dzGqHfg +iFGfmppKamoqaWlpZGZmcvvtt5d+xwOEL+uveUqpuZ42N/lrKqVeRSvXQ9A+vf4hhnfjAryJnhr7 +FR2yspOxvw2wDNiMHqFs4JyiPgUYgzYpXoteq1JqPNL5ET5Y+wG2Nq1hy5bSbKpIbDi2gb+T/+b+ +n47q0VN5THu5kpAALjfR2LF6pPKX1/hw5yk7dmBqfXF59yIfSina1mlLkmULV10F339f3j2q3JRX +jHoRITc3l7y8POx2O7m5uVgsllI7Tk/4sv6ajB4ZeNqcKKXeRIfzzQDaisiLIpLmqWLRFlxfoEcf +GUAvI+ki4AvRVl6t0ALqImPbIyJtjbKvGftKjY71OlK/an0Wqr2wZ0/heBDlxJTVUxjffDghH38K +JRyqBgSXkQpob+djx4Ifa7nOK86ehdhTO6nSqWIJFYA2tduwNWUrQ4aU30zohUyh2EBe5uJatGjB +l19+yciRI6lduzbz589n3rx5hISEEBoaypw5c/jkk0+oVasW3377LYMHD3aW7dSpEzNmzGDkyJHU +rFmTFi1a8JmLWZ+3dpcvX05kZCQ33HADhw8fJioqimvLYcq+KA4lI4FGIrLTQ7odHenRyjmlfhTn +1pRsxY2i3ij7D+BiERlWnr6/3PHFxi/4avNXLHx6o9bSNijVwZFPUrJSaPFeC5IP305kSAS8/Xa5 +9gfQAaFWrIBPzvkSzcnRsmbRIu1C7UJg40Y4ftUt9J1+K1Sw6YgP//6Qv5L+YurVM2nUSF+qTdxN +OldQgr6/yp7S8v3lb+THG9GjljCgsVKqPfCy6wNdRPzyI+aBWWjBAeXopsUdt7a5lad+eYrshHii +du8ud6EyY90M7o+7jsiJs2HbtnLti5OEBPjii3y7IiJg5Ej4179g5szy6Vag2bYNrmQHtKx4Lmla +127NJxs+IToaHn4Y3nwT3n+/vHsV5HygvNy0rAWqAetd9m0uiS0z0Mz4fAqwA98Yv8vVTYs7Jq2c +JL90qyO2Tz4OWJ3FwW63S8LbCXJ0xFCR0aPLtS/52LNHJCGh0O6TJ0Vq1BBJTi6HPpUCzz9rlbyQ +CJHMzPLuSiFOZZ+Sqv+sKna7XY4fF6lVS2Tz5vLulf8E8n4N4h+ezjml6abFBYuInCmwr6Rj1TeU +UtvRVl9ngecL1Fsublrc8US3J0iqGcqvS2aW6xD9r6S/qG4Noc7sn2D06HLrRyEaNoSkJB1C1oVa +tWDIEDCsI897Tq0/RF5MbLl6JvZEzciaRIdFcyT9CHFx8M47cPXVerT41VeQm1vePQxSWfBXqGxV +Sg0BzEqp5obeY5WvQt4QkVuALejAXyeAk0bSQMrZTUtBQkwh3Hrdk2Tv28m1X17LuqPrfBcqBb7Z ++g2vHG6O6tEDytsVgythYToE86nCLt6eeEJbPBsm/Oc1ubsOYo+vQOe9AA5lPcBdd8Evv0DTplrV +1bu3NjQIEqS08VeoPIY29c1F6z/SgcdL0rBSagBwWEQKOra5CDjs8juJc9ZfrgbeRyhl6y9Xopte +zMDIDgxoOYAbZt3AhCUTfBcKMD/s+J6rF+yEUaN8Zy5r6tSB48cL7W7aFHr10rr8isQ33+j1NG7k +oFtEwJx0iLBmjUq3YyWgde3WbD2x1fm7XTst1H/9FeLitJ4lSJDSxt94KnVEZDww3rFLOIfVAAAg +AElEQVRDKdUZbULsEaXUr4BrlCiH9ddzwLOAvzFWikUgFPVO6tbFdOIEI7uM5I5L7uDyjy6nW8Nu +XNfsuhL30x/2pO6hyeFMwvOiy39dijvq1tWBRtq2LZQ0ZgzccYdeEBni7xVXimzbpqeFrrkGBg/W +wTF9rdZOSYFG6jDhTUs3Rk1JaFO7DX8lFV4cpBS8/jr07AnPPlsx/oMgFYfyUtSvAy5y+X0VJVDU +A5eg16ZY0aMfAY4DceiFkAvRCvntaMF1OVAXrZzfhFbU/wS876WNYqqvPHDkiHbaaPD15q+l56c9 +A9uGF9778z2ZP+gSkXHjyqzNIjFkiMgXX3hM7tVLZPr0MuyPF0YOy5RNl94ttjcmStu2IgsW+C7z +++8ic2r/n8i0aaXfwWKy7MAy6fZRN4/pl18uMn9+GXaoCAT8fg3iE0/nnDJS1D8EfK+UqquU6o/2 +JNy/BIJsC9pE+RkRCQcOoNepnEDrWa6inN20FKJ2bf26aiyAvLnVzWw+vpnDZw77KBgYft77M4lr +U+DWW31nLg/q1PEaenniRHjxRfBjYXCpYrXCJV+Pp2nNVEzvvM3z1/7l12LBvXuhScghaFRxp79a +xbZiW8o2j8YkQ4cGF0YGKX38EioisgYYBfwCvAhcLSKBeJq6WnE5vl9CBXHTko+wMKhaFdK0k4Aw +cxj9mvdj/u75pd50ni2Pw2uXEJ0r2g9ZRaRWLUhN9ZjcuTMkJsKUKWXYJzcs/zGdIZZPifrqIxg3 +jhu2v8lPP/l2lrBnD9SzVmyhUju6NiGmEI5luhfuAwZo5X0FcQwRxGDYsGG88II7J++Fady4sdMb +ckXFb99faGurKPR01Ux3vr+KwUil1AZgMeCwR60wbloKERcHJ865Mbuh+Q38uKv0A3itSVrD7Uk1 +MPXrX6YBuIpEjRpOgeuJ117TQuX06TLqkxtSZvyP5GY9oF49uPdeIpctpF6VDHa69RNxjj27hRoZ +h7T5dAWmVe1WbD+53W1aw4Za9vsZ8ynIecbkyZNp27YtMTExNG3atNwiQPpS2ZWoV14U9eOBaehV ++WI4oXwLeKAk7RUkoIp60ELl+HFo1QqAa5tdywPzHiDXmkt4SHjJ6vbCykMruWGfGZ4sG6OAYuGH +UGnaFPr2hc8+K79lNrFrfybvTsMRREwMdO3KA3m/sWrVIMff6pbju86gTEqbTldgWse2ZnvKdno3 +7u02vXNn+PtvuPTSMu5YkDLhiy++oF27duzZs4e+ffvSqFEjbrvtNq9lykVRX5QNve4k2vh+N/Av +IN5D3sfQyvgdwAlj31hgARVNUS8icsstIt98k2/Xpe9fKn8e+TPwbblw8+fXS150pF6iXlFZsECk +b1+f2VasEGnRQsRmK4M+FcBmE0lS9eXUX3vO7Xz1VVnf5ykZNsx72cRqG8XSsk3pdjAATPljijw6 +/1HP6VNEHnmkDDvkJ6VyvwaQhIQEefPNN6Vt27ZStWpVGT58uBw/flz69esnMTExcs0118hpl+iw +P/zwg7Rp00Zq1KghvXr1ku3btzvT1q1bJx07dpSYmBi5/fbb5Y477nBGfhQRmTdvnrRv316qV68u +V155pWzatClfP3xFfnQwatQoGTVqlMd0T+ec0lTUK6VWGp8ZSql0ly1DKZXuodj7QLZS6lK0C5a9 +6GBdBeu+GR3rvi3wIbDCSNpCBYin4hbHSMWFrg26svrI6lJrUkSw/r4SadlCz11UVGrW9KpTcXDl +ldov2KJFZdCnAuxfdZRIlUPNy1w8LXbtSvOTf/DHH57LnT4NdXIPYW5ScfUpDlrFep7+AujYEdau +LcMOXUDMmTOHxYsXs3PnTubNm0e/fv144403SElJwWazMXXqVAB27drFkCFDmDp1KikpKfTr148b +b7wRq9WKxWJh0KBB3HvvvaSmpnLrrbfy3XffOdtYv349w4cPZ8aMGaSmpvLQQw8xYMCAYrmwX7Fi +BW3KwZurryBd3Y3PqiIS47JVFZEYD8WshrQbCLwnIv8GqrrJ9y+gKTqqZA/AEdapYirqoZBOBUpf +qOxJ3cMVhyGsZ59SayMg+DH9BVoldP/9MGtWGfSpAIfmbuBwrQ759VIdOxK1dxMHD4hHy7Tdu6Fj +7CFUBVbSO2hVW1uAeaJ9e61TsVrLsFMXCI5wwvXq1SMxMZGuXbvSrl07wsLCGDRoEOvXrwfyhxM2 +m82MGTOGnJwcVq1axerVq53hhM1ms9dwwkophg4dSnh4OKtXF+0ZM2HCBESEYcOGBfQc+EOxl0Ep +pQ6JiLu7LEMpNQ499XWVUsoEhLrJlwb8AFyHdlbZAL1WxaGod3V9fxF6TcseKeD6vrj9LxZ16sC6 +/C5aujboysvLSi9wyIZjG+iTHA73X1FqbQQEP4UKwE03wauvaiskU0l8WxeR3HVbyGraLv/OGjVQ +VavSq9ZhtmxpxOWXFy63eze0qnK4wivpARrGNCQjN4PTOaepHlG9UHpMDNSvbxyTFx1SRUS9FBgj +FZlQPP9950s44ffee48vv/ySlStXEhrq7tFbupRkba2nf/h2YAg6Nv0XaGERbcSWd11RHwLUEJGu +xur8b3EfdrjiULt2oZFK85rNOZZ5jIzcDKqGuxuQlYzNRzdy/d50PW9UkaleHc6c8UtSxMdrfffW +rW4X4Jcaoft3YbqqU+GE1q252ryN9es9C5WbzIegUQU2lDBQSmkLsJTtdGvYzW2eli1h587zT6gU +VxiUNfXr12dLgUixjnDCgNtwws2aNQPOhRMeN25csdr++OOPmTRpEitWrKBevXrFqqOklESoePqH +M9AOIW1KqUeBi4EFIpJvUlAp9TAwB/Q6GKWUTSlVC+3ry3UEVK7xVPJRq1aht3GzyUzzWs3ZdWoX +neq7eWCVkJQNvyPVYrQblIpMSAhERekA6X5YSPXooeN6laVQqX5iF1GX3Vk4oXVrLju8ja82uBca +u3dDXUvFXqPiikOv4kmotGgBu3aVcacqEbfddhsTJ05kyZIlJCYm8vbbbzvDCYuIM5zwiBEjmDt3 +Ln/99Re9e2trvQcffJCbb76ZPn360KVLF7Kysli2bBk9evQg2od37K+++orx48ezdOnSfKMfXwTa ++surUFFKPekpCR1f3h3LgUSlVA30Ysk16NHLXQXy1Qb+o5Q6anyPE5FTxvqX35RSw412ItGKelFK +WZRSu9ECLRQY4a3/rkIlIHhQRl8cezE7Tu4oFaEStnEz9k5dAl5vqeCYAvNDqHTuXPYx7Otn7Sbs +imaFE1q3pvm+v9mwwX253buh+pnzTKikeFbWt2xZ9uf+fKe44YSTk5Np3769M5wwaIX/Aw88wHPP +PUf//v09hhPes2cPkZGRdO/enR49evhs9/nnnyc1NZXOnTsjIiiluPvuu5k2bZrXYyv4wv1SCUOU ++xqpeJvPecfDfiUi2YZQmCYik5RSG93kuwL4GGiPFhCO0IH+xFOhQN6yoWZNt25tL66lhUqgOZ1z +mmYH0om+vgI6kHSHQ+gmJPjM2qlT2UYmzDiZS005RVhbN+tl27QhduZnbN3hfvZu7y4bYdnH4KKy +XWtbXFrVbsVH6z7ymN6yZaFAnUF8sG/fvny/P/88v0Hr8OHDGT58uPP3wIEDGThwoNu6OnbsyLp1 +nsNn9O3bl759+/rVD3/TyhKvQkVEiiOylFKqG3pk4jjLhSbZjemwoUaBQ8A/jSRHPJWJRtoCtPXX +QYx4Ksb+O9DxVH4uRh+Lh8MViUg+C6KLYy9mzo45AW9u0/FNdD0VhamiumYpSBGU9ZdcoqdgrNay +8Zp7dM0RokLr0yDEXDixRQtC9u2iRg04cCB/bPdTpyDOdlT/92Fhpd/RANC6dmuvFmDB6a8gpUmR +bW+UUr4iVD2OdunyPxHZqpRqAizxUl8icExEHGK2QsZTASAyUguTAtGOHNNfgWbj0Q1cnJSrA2Oc +DxRBqERGajXRgQOl2yUHaRsOklrFw/RVXBxYLHRrmVrIhcnu3dDtovPDnNhBkxpNOJ51nIzcDLfp +9epBTo7ff1WQIEWiOO+IXu36RGQZsEwpFeXqpqWA9df4/2/vvMOjqtIG/nuDgCAkJEBQpEoRO7oI +IoigLjYEVyygoMiKorK6VsAGrkqwoOy6lpUiKggW+FRQEVwNiArCCtIRMRQp0lsQSHm/P947yWQy +SSbJncxMcn/Pc5/ceu57T87cc895m6pOdy7pDUwugRxF4rqiHnKneKpXz9l1cp2T6XNGn9KXHUD6 +b79SWSrZWyAWKEanAtCqFaxeDc2DqDncpkbmXjJPOTX4QRFo0YJOJ6xl2bJ2+M9arF0LrZM2womx +06kcE3cMpyefzk+//0THRh3zHReB5cvNvNjDI+JhWoCnizjeHlgJbHS2z8J0K4HnnQv8AGQAi4E2 +Gu1hWlRVBw5U3bgxPGUHkpWlumVLiS4dPny49unTR1VVN27cqDVr1tTs7Gw3pcsfMuKbb1SXLw/5 ++nffVV0Q3gg3ofPqqzo9ZZled13e3S++qDq763OqDzygNWrU0LS0tIiIp6pF3t///zFw+kB95YdX +ilV+v3798oQLKQ2dO3fWcePGqarqpEmT9NJLL805JiK6bt26POeH8nv1l++bb77RVq1auSJrpEhN +TdUGDRqEdK7/79ktCqpzyiifin8n9FgRp4wGLgV2Oef/hOVHCeQ54CNgHpYF0pfsdAXRGqYFTLvc +sCFNmjShXr16/OE3FTZu3Di6dOniym1SU1NNY1yKUYrPUqRhw4bs37+/UMsRV+jYEU47LeSvnt69 +oW20GLbdeSet+5xO797kkf++++CSvidAhw4cOHCAJiEYIYQL//sXFi49NTWVFy99kTvbFGwc+dZb +b3HBBReEQ8x83HjjjcycOTNn24122LFjR1atKtjCLRQ2bNhAXFwc2RHMBVCcugj779clQupUgsT+ +2i8im0Tk/xydSR40f66VrMBzgK1YOuHJQC1yfU5OI1rDtPghImRnZzN69Oh8+0uCBiRWcnU4WsYU +V/asrGDNo+SUtLwGDeAvfwkif58+diBGSE1NpVrlaoW2RXVMTiNBYFuPFL46iBZ5yguhjlRGAw9h +ivEG2Iv9XWAKZhbszyYROR9QEaksIg9i01iBDAGaY971z2HKfYjmfCoBPPTQQ4waNYr9+4PH1vzu +u+9o27YtiYmJtGvXju/9ohZ26dKFxx57jI4dO3LccceRlpZGly5dePzxx+nQoQMpKSn06NGDXbt2 +0adPHxISEmjXrh0bN27MKePvf/87jRo1IiEhgXPPPZd58+YFlcP/i2z+/PnUrFmT+Ph44uPjqVat +Gic55k6qysiRI2nevDl169alV69e7PVLfvLOO+/QpEkT6taty4gRI4Ley8ett97KnXfeSdeuXYmP +j6dLly55ZI+Li+PVV1+lZcuWtGzZssj6Wr9+PRdeeCEJCQl07dqVQYMG0bdv3zzPN378eBo3bszF +F1uctPnz59OhQwcSExM5++yzmTNnTk55EyZMoFmzZjm5JyZPNrXeunXrmDBhArVq1SI5OZnevXOd +JePi4nLMNvfv38/NN99McnIyTZs25Zlnnsk5zzcKeOihh0hKSqJZs2Z5vtT9mTBhAt27d8/ZbtGi +BTfccEPOdqNGjVi6dGme+48ZM4ZJkybx3HPPER8fn8d0dfHixbz++uskJibSu3dvjh49mu+eq1ev +5s477+T777+nZs2aJCUl5RzbvXs33bp1Iz4+nvbt25OWlpbnuq5du1K7dm1OOeUUPvjgg6DPFEhh +o6J58+bRyM8IItR7zJkzh4Z+YXO2bt3KtddeS3JyMs2aNcsJcwKwcOFCzj33XBISEjjhhBN48MEH +AXJ8P2rVqkV8fDwLFizId58nn3yS66+/nr59+xIfH89ZZ53F2rVrGTlyJPXq1aNJkyZ8+eWXeeTo +0aMHtWvXpmXLlowdm2vaffjwYfr160dSUhKnn346CxcuzHOvwp4hpghljgz4Kci+JcGOYVNUk7A4 +XkexGF8rsM5hmfO3OzAbuNq55lpgtrP+MnCjX3ljgWuAPwGz/PZ3BD4pROaSTDOGjG/+umfPnvrY +Y4+pqurYsWO1S5cuqqq6e/duTUxM1EmTJmlWVpZOnjxZExMTdffu3apqc86NGzfWVatWaVZWlmZk +ZGjnzp21RYsWmpaWpkOGDNFTTz1VW7RooV999ZVmZWXpzTffrP3798+RYdKkSbpnzx7NysrSF198 +UY8//ng9cuSIqtocbN++fVVVdf369RoXF6dZAfHmMzIy9MILL9RHH31UVVVHjx6t7du31y1btujR +o0d14MCB2rt3b1VVXbFihdaoUUPnzZunR48e1fvvv18rV64cNAz3sGHDtF+/fhofH59z/r333qsd +O3bMOUdEtGvXrrp37149fPhwkfXVvn17ffjhhzUjI0PnzZun8fHxeZ5PRPSWW27RQ4cO6eHDh3Xz +5s1au3ZtnTlzpqqqfvnll1q7dm3duXOnpqena3x8vK5du1ZVVbdt26YrV65UVdXevXvrRRddpKqq +R44c0W+//TZH5ri4uBxdQN++ffXqq6/W9PR0Xb9+vbZs2VLHjx+vqqoTJkzQKlWq6Lhx4zQ7O1tf +e+01rV+/ftB29Ouvv2piYqKqqm7ZskUbN26sDRs2VFXVdevWaVJSUtD7B9N/NGnSRNu1a6cPPPCA +7tmzR0855RT9z3/+E/S+EyZM0AsuuCDPvn79+mmdOnV00aJFmpWVpTfddFPO/z89PV0bNmyob731 +lmZnZ+uSJUu0bt26eUK6++OvUwm8l0+n8vnnn2ujRo100aJFCgS9R506dXLu4f/MqampOfWUnZ2t +f/rTn/Tpp5/WzMxMTUtL02bNmumsWbNU1drOxIkTc55jgaPI8/0uCtM1Dh8+XKtVq6azZ8/O+Q02 +btxYR4wYoZmZmTpmzBht2rRpzvkXXHCBDho0SI8ePZpTR19//bWqqg4ePFg7deqke/fu1d9++01P +P/30kJ/B//fsFgW9IymlTiXUTuV74HpsZBPnrM9Xv87FWa8E3BdimfsDtvdqrqJ+sN/+meQq6lf5 +7e9FEYp6b/EWb4md5b333tNOnTrlecHdcccd+o9//ENVC+5U5s+fr40bN85zXUpKSs4HWKdOnXT4 +8OG6MyAfUUEfW/4MHz5cu/rlCZo+fXoeo5cDBw5oXFyc7tu3Tzdu3KjHHHOMpqen55w/dOhQvdVJ +1nPSSSfldBKqqm+88YY2bNhQ+/Xrp/379y/0GXydSnHyqRRFYf8LLQNF/U2Yo+J2Z+kL9BGRasAg +30mqmoUFkwyFtSJyIYCIXIxZewF8AvQSkSoi0hSbIvMp6veJSFuxyeCbsSjHQVFVCecCrAcudtYn +kpu58mtn32Dg/YBrpgCPOOupwG0Bx1OBv/ptPw286bd9CbDWb/shbGpxr7NkARc5x4Zj04gCNAGy +MedR37UDMSu9mn77DgH7sNHlHqfMQ0B94HXguQB5t/rqIEj9TAhy/g6grbOuQHO/YwXWF3Ae8HvA +sZQgz3eM3/FXgcMBz3IQ+2ARoCs2Wt4LzABaOfvrYbq8LVhun/5+ZSqWrqGec7/qfscuA3521vsB +3wTIq0CzAurqHeB+R+YbgWeBO5w6vD9YGc6xpwpqk4FtIMg9g8mYp0ygM7DJWX+Y3JkHX30ewCw7 +g5Wf05YD7+U8xzb/9gE2jTl//nySkpJISkoiMTGRd999l98DchgFsnHjRjZv3pznupSUFLY7wV/H +jx/PmjVraNWqFe3atePTTz8ttLxAAqMR16lTJ0cfVa1aNVSVgwcPsnXrVpKSkqju527QuHFjNm82 +dfGWLVto0KBBnmM+9u3bV+gzhMLo0aNzpnSPP/54+vfvnxM5uSAKeb+VmJD8VNQcE68q4HDgRP48 +Efk38B6Qk6FCVQOdJu8AXhGRKtiP/3bnvJUi8j72wssA7lLN0aTdjTX8Y4HPVDX4RHXZMxz4EetY +fGwBegac1wgzl/ahlBDHafQhoIuqrnT27aYIPyK/a58EOqiqf6vbiL1E86WscmK0tfLbrg4UlTUs +Z9JbRGoASeQNAur//IXV11YgSUSOVdXDfmUH1p//9ibgbVW9I5hgqjobmC0iVTH93Bigk6pux2mL +ItIBi0M3R3OdcwF2Ym2zMZa1FGe90ACnhTAX+301cWTZh33InYdNBwd9hBLeq6TXbwJSVfXSUt7X +d+/rgPEisllV/wVmpdi5c2e++KJ4QTIaNmzISSedxJo1a4Ieb9asGe86CXymTp3Ktddey+7du103 +VKhfvz67d+8mPT09J/jjxo0bc6ITn3DCCWzatIlTnPDQGzZsyLk2Pj6+0GcIhR49enDLLbeQmJjI +3r176dmzJ8888wwpKSmleKriE6r1VwPH0mu7s0wVkYIsr1pjFlz/wF6yowiS615VF6lqO1U9W1Xb +q+piv2Mp6ijqVXWW3/7/qaOoV9UIZTnPj6quwzrRe/x2fwa0EJFeIlJJRG4ATgGmByujBNTAXmy7 +nFHdExQeq00ARKShI+vNjtz+/AcYISKNnHPriohPi/wh0E1EzheRytj/t6hf5RXO+VWAp4DvVbWg +xBAF1peqbsSSuQ13jD/ak/8jJ1CWicBVItJVROJE5FgRuVBE6otIsoh0dzrGDGwEk+U887Ui4jMA +2YuNSPLYnKpqNvA+8IyI1BCRxsB95MavKy5zgC5ANad+vsFGPrUxH65g/E7pUkX8DjRw/pehMANo +KSJ9ROQY5//QRkRaFXllfgT7iLgYuMeJWE63bt34+eefmThxYk6WxEWLFhX5om3bti01a9bkueee +4/Dhw2RlZbFixQoWLVoEWPTenTt3ApCQkICIEBcXR926dYmLi2PdusCfQX6aNm3KCy+8wIABA1i/ +fj233XYb27dvp1u3bqgqvXr1ombNmpx//vkMHTqUqVOn0rx5c1JSUli8eDGrV6/m+uuvJyUlhblz +53LGGWcwcOBAdu3axeHDhznxxBNznmHatGm0bt06xzBgWWCYh0JkTExMBMwCMi4uLiLh70Od/noT +m5aq7yzTnX35UNUuQZaL3BG3aETkMhFZLSI/i8jgMN4q8EvvH0B1335V3Q10wyzldjp/r1TVPSIy +DuiAjRZ8cidivjnPiMgXIpLgd2yoE515vHMPsJhnX2Dm1WnYNFWgKXcweS8CkoEPJTc1tK/V/hOb +UpwlIvuA74C2zvOsxEaKk7GpC5+N7VgRucf3DCIyS0TWYNNLH2KjuF1YTLcGIrJKRLoG1l9h9eWc +chMWhHSnU9dTgCNBns9X3m/OPR/Bpt02OGUei+npJmHTN+mYH9VgEZmFdazrxNJlf4R9KPR26l8w +AxGc/YeAX7GRxkRVDfqbCCZfgKxrHVnmOtsHsDTc8/xG6YFljAeuEZGjIjLNaT/1gLcKaj9+dQ/w +FWZAs01EipxjcUa0XTFd5hZnGQkUFBCtsJGQAJ9i75SD2NQnNWrUYNasWUyZMoX69etTv359hgwZ +wpEjRwopyqziZsyYwZIlS2jatCnJyckMGDAgxypz5syZnHbaacTHx3Pffffx3nvvUbVqVapVq8aj +jz5Khw4dSEpK4ociQjdPmzaNF154gYYNG+akEx4xYkSOZeW//vUvJk+ezPLly7n22ms5fPgwr732 +GjfeeCNXXXUVjz76KA0aNKBLly7s3LmTkSNHUr16daZOnYqIMGPGDL7++muuu+461q9fz+mnn84V +V1xB9+7dQzaTnzx5MgkJCSQnJ5OcnMw999xT6Pkisk9E7vH/7YbYfgpGQ1OqLwlln7P//iDLX4HW +IdxnHPYFtbSA4zcCPznLPOCMgONxwC/YVERlzMelVSjPWJYL9mJq7f+c2Dz6w876YGCks34q9rV6 +DDY98gsWCTqS8h/v+39iI6Y12NSY/zMswl6KYXkGrFMZVsJrqzt/KwHzsQ4+Zurfkes+bDT2SQy2 +n1+xBH3++zSaadKkib777rs52z179tS77rorZ/vll1/Wv/zlL6qq+tRTT+kNN9yQcyw7O1sbNGig +c+bM0blz5+qJJ56Yp+zzzz8/xwDhzjvv1CeeeCLP8ZNPPlnnzp2bI0coivpffvlFW7durS+99FKB +52Ad/xZsKtm19hPqSGWXM+yt5Cx9cDzmg9AGUwL7fEvuwIbyY0SkqPS/b2Le+AXxKzbvfRamxB4T +cLwtpsjeoBYFeQr2tRpVqOo8TNnpTw/gLWf9LSwCM5j59RRVzVTV9ZhBQ0T90FV1m6oucdYPYsYC +Dcj7DL+Qq4Mp9TM4Uy0niXGZU+ZHJZT/kLNaFfsQ2UMM1b8z9XwFZm7vI2bkx0YqxU8kLeLOUkLc +SCe8ZcuWItMJjxo1Ko/C/rfffitWOmEwPdKQIUPyhegPwjo1Z3XX2k+o/9j+mBnxNkxpei1m0RGM +BsA5qvqAqj6A+ZckY1MMBV0DFPiy9T8+X1X3OZvzye/8GBjhuOwjGZecZFX9HeyljdUZFBy1OSoQ +kSbYqGs+UM/3DNjUkC9VnRvPcDxmUXQAc8YdqBYCqCQyx4nIYqw9p6pN7dWLofp/CTPS8J9iiiX5 +FTOSWCgit4V+lbqzhJn69evnUcJDbjrhE044IWg6YR++dMK7d+9m9+7d7Nmzh4MHD+ZxiA2VjIyM +PJZoBfCu89e19hNSp+J8+XdX1bqqmqyqV5PfUsdHMnnnujMcgf8I2F9abiOvJVV5I/ytv5Q4Fl0f +Avc6I5YcmVW1P9axuIKqzlDVRqpaQ1VbqWqRn2CFlJWtqmdjH0AXiEhnCrckixpE5ErMvHoJhRtK +RKX8Dh1U9RxstHW3Y41Ybrj++uv59NNP+frrr8nMzOSFF17ISSfcvn37nHTCmZmZTJs2LY8uZ8CA +Abz++us5+9LT0/nss89IT08v6HY5jBs3jh07dgCwcuVKRo4cmSerZAH4Qha413Xyk1sAABukSURB +VP4LmxsrbMGJQhxk/+OYee0wTEm7CHgC+2qdFEK5jSlAp+J3ThdMyRg4L3seMNNZD5uTlrd4i7d4 +SzlfVjnv0aDO6G7oVIIR9CtJVZ/C7Pz3YlNZA1X1H6qarqqBeeqLf1ORM4E3gO6aaxnkYyHQ3DHx +jJgi0o1l2LBhEZehIsruyR/5xZM/souDz7E8qDN6Ye/o0iRy1UKOZWC2/eqsFwehgA7L8Z+YCvTV +/D4WqGqWiAwCZuW72MPDw8MjVEYCaOHO6EEptFMRkQME7zwEqFbANfdieVCmOudNFJE3VLXIkJsi +8i4WGqK2WN76YZgdvKrqG9jUWhLwqpg7bIaq5rFEUPOyP1lECn1wDw8PD4/gqOpev/UULCxSSBTa +qahqYR7aBfFXbM4tHUBEnsUCUoYSx/kPzHdgjarmS8yuqgNE5A/gcsxp7fYSyBcTuJL6OELEsuzg +yR9pPPljGyliJFP8As07+1x1YjSJyLHAQlU9I4RrO2Ietm8H61RE5HJgkKpeKSLtgH+q6nkFlFXU +KM3Dw8PDIwCxxGUldugpjU6lIN4EFojI/znbV2Oe8kWiqvN8SvYC6AG87Zy7QEQSRMTfN8LDw8PD +I4K43qmo6osikkpujKRb1S9YZCkpyBHH61SKYNkyeP99OOzE+G3SBO6+O6IilTsOH4Y33oDffgNV +c96++25oXNhnkke5YN48+PxzyMqC7Gz7//u46SZo3TpyspU1rnYqIlIJWKGqrTBflYgyfPjwnPXO +nTtXqLlOVdi6Ffbvh/XroV8/uOUWSE6GAwfgqae8TsUtsrKs037wQahaFS64ACpVgkmT4OyzvU6l +vLF3L+zbB0eO2LJwIQwdCnfeCTVrQlxcbjSYmTMhISG6O5XU1FRSU1NdK8/VTsUx6V0jIo3UwpW7 +zWb8cnRgHtEF5rDw71QqAgcPWoexaRPccQds3gyJiba89hr8xYkrvH27bXuUjowMmDMHHngA/vgD +rrkGnn4ajnF+VYsXW4fjETuowqFDcPSorfsvYKP9oUOhVi37gKha1T7UPv8czjknf3n790d/Gwj8 +4H7yyScLPjkEwqFTSQRWiMgP5E3S1b3gS/JQoJ8K5ohzN/CeiJyHpSCusFNfWVmwcyds2QKvvAKT +J9uXUlIS/O1vMHBg8Ph5lSpFf0OPZjIz4T//gcGDoVkzeOQRuP76/HXt1XNsoGov/y1boH9/WLIE +jj3WjgXGomzQwD4WmjULreyK2AbC0ak8XtILi/JTUdXPROQKEfkF67BudUPgWCIry6azPvsMHn8c +KleGevXg8svtR5GQUGQRFbKhu0FWFkyZYtMcp5xiL5cWLQo+36vn6CYzE/77X+jd29YTE61T+e67 +UgUzzkOlSjairUi4rVO5GnPjX6aqxcsJarwNnIOZFY/TgKRHIlIbyxF+EPNnOZMo0N2UBUeOwIgR +8PzzNtw+7TT4/nt7uRUX72VXPDIybNpj4EDTj3zzDZx1VtHXefUcfaxda4rzJUtshFK/PkybBuFS +t1bENuBapyIir2JphL8DnhKRtmpxwEK9Pg74N5ZidAuwUEQ+VtXVfqcNwpKDXS4idYA1IjJRVTPd +eo5oIzUV7roL1q2DP//Z/pY2Q2hFbOglIT3dRiXvvQfNm8O338KZ+bynCsar5+ggLQ1uuAGWLzd9 +14gRMHdu7hRXOKmIbaA0ASUD6QRcpKpDsSmsqws/PR+hJNjaRm4e9prArvLYoWRnwxNPwIkn2tB8 +5EhTwM+YUfoOBSpmQw+FHTvgiivg+OOhRg2bDgHYswdWrChehwJePUeaMWPsN3TmmTY62bnTLLcG +DSqbDgUqZhtwc/rrqKpmAajqISc2V3EIlmArMMPYGOC/IrIFS2Nb/Mw1UUxWFjz5JLz+Opx8so1S +mjUzE0U3qYgNvSBWroQBA0xPtWuXWXKNHWsGD9Wq5VpylQSvnsseVRg+HMaNs/r//HNo1QqqVImM +PBWxDbjZqbQSkaXOugDNnG3BFO3F/M4LylDgJ1XtIiLNsOxxZ6oliMpHrPipqMK//22+I2eeCfPn +Q9Om7ikLA6lUKddBK1z3iGZmz4YhQ3K/XEeOhG7doE4d60jcoiK+UMqaL78067t9+0zZnp5ueq+v +v7bfUGk+CtwgFtpANPuplEBlnIfNQCO/7WA+KB2AZwBUdZ2IpGF50BcFKzAW/FQWLoTbb7cX/Jw5 +JVO8FxefeWR2tjX6isCCBfDYY+btvmMHTJgAZ5xh5tc1SxI2NQRi4YUSiyxeDPfcY//HXbtsmqtV +K7OErFLFprzcHt2XlFhoA1Hrp6KqG4o+q1D8E2xtBXoBvQPOWQVcAnwrIvWAlsCvpbxvRNi3z5yo +3n/fRinXX1+2PwRfYy/Pncqnn8Izz8C2bRZCJSUF2raFhg1NZxJuYuGFEiusXg333WfTlFu3wksv +wXnnmY6xVq1IS1cwFbENRHhwmEtAgq04zKR4lYjcQW4+lRTgTRH5CZtWe1hVd0dO6pIxbZqFSOnR +wxTA9eqVvQzlubGPGWP+JMuWwfjxNvo78cSyU876KM91XBZs3AiPPmoRIpYuNV3JJZfY/zIUf6xo +oCK2gajpVPzwz5OMqv4n54DqThEZBbwEVMbyqUyOhJAl4ehR88J+7z346CNo1y5yspS3xv7HH+YM +Om+e6UleegnatIG6dSMnU3mr47LgwAHrSFassI7k7rvNIbFpUwuCGmtUxDYQNZ1KKH4qIpIAvAJ0 +VdXNjq9KTLBkifmb1KplP5Y6EZa8vDT2/ftNUfvll2bkkJJinXX16pGWrPzUcVmQmmojzB9/hD/9 +yaaGmzePzY7En4rYBtx0flxGIXnrQ7D+yvFTccrz+an4Oz/eCExV1c1OmTtLJXQZkJVlVl3//jc8 ++6xFC44GPUasN3ZV05eMHw8XX2wmpOefH13WbJUqmUWSR3AyMy1CxPLlMGuW/U5uv92iPEeLor20 +xPrvrCS4OVLp5vz1BVR/x/l7U4jXh+Kn0hKoLCJfY34q/1LVd4hSNm60TgTgf/+LrhDosdjYVWH6 +dPuqXbXKoi1PmmQK22jqTHxUqmThdTzysmGDBeScM8f0XH372gdCrI9KghGLv7PS4rr1l4j8WVXP +9js0RER+BIa4cJtjsNhgFwHHAd+LyPeq+osLZbvKF1+YU93tt5tPRKTt5QOJpcaenm46kpkzzbu9 +Xz+bIunRo2ysuEpKLNVxOMnKspHkihWWnuG//zW/oL//Ha6+2kyByysVsQ2E41UnItJBVb91Ns4n +tHAwofip/AbsVNXDwGERmQucBQTtVCLh/JiRYc50r74Kb79t8bqikVhp7N98Yy+fk06yefZLLrEc +FrFArNRxODhyxKZ816wxHaII9OoFxx1nyeI6dYq0hGVDLLSBaHZ+9PFXYLyjVAfYC/QP4bpQ/FQ+ +Bl52MkxWBdoBLxZUYFk7P6almbXK0aPmFR9N012BRHtj//13C1fz6qsWALB//+ic4iqMaK/jcPDz +z2Yy/9lnNors3t2Sw3Xu7G60glghFtpA1Do/+lDV/wFn+ToVVd0X4nVF+qmo6moR+QJYCmQBb6jq +SrefoSR8/bV9iQ0aBA89VPY+EcUlWhv70aMwcaJ1JJ062bx7q1aRlqpkRGsdu83y5RZja8cOeOst +iwjcpw/89a/RYZQSSSpKG/DH9U7F8XQfAdR3QtSfCrRX1XEhFlGgn4qz/YKIzMFC7BeYSrisyM6G +f/7TprymTIEuXSItUWhEY2P//HOrx7g4GDXKdCaxTDTWsVv88IOFS9mxw9r/jTdadOePPzbDCQ+j +PLeBggjH9NcE4E3gUWf7Z+A9oNBOJcR8Kr7zRgIlSQLmKvv22bTM1q2x90UdLY1dFb76yhxCZ882 +n5N+/cqH8jZa6tgtvvvO8vmsWGH6wiuvhPh4m+o699xISxedlLc2EArh6FTqqOr7IjIUQFUzRSSU +ag3FTwXgb8CHQESb8fbtcNVV5nA3aVL0T3cFEg2NPS3NRiQzZ5pZ6Q8/RNYD3m2ioY5Ly/LlpidZ +sQJee81G4snJlrCsadNISxf9lIc2UFzC0amkO2l/FUBEzgNC0asU6aciIvWBq53Q94E+LGXG+vXW +oVx+uTk0xpoCGSLb2DMzLUrwI49YIM3vvrMXVXkjFl8oO3aYT9WRI2Ys8cgj5oyYlGRRC049NdIS +xhax2AZKSzg6lQeAT7B8Kt8CdYHrXCp7NDDYb7vMX+czZpgCcvBgi5oaix0KRKax+6a6hg41S6Dp +0yMb/yzcxNILZc0aS1g2aJAF4DzuOBt9T5tWccx/w0EstQG3CIv1l4hcCJyMvfTXOOmBiyIUP5U2 +wBQnq2Qd4HIRyVDVT4IV6LafyssvmyL5o4+gfftSFRVxyrqxr1tnncmKFeZ3ctttsdshh0q0v1Ay +M60zmT3bQqS0aQOjR8N1bn0CekR9GwD3/VRQVVcXYB0wMGDfjBCuq4Q5MTYGqgBLgFMKOf9N4JpC +jqtbZGerDhmievLJqmlprhUbUdq0UV2wIPz32bZNddw41Tp1VO+/X/XQofDfM1qYOFG1V69IS5Gf +HTtUP/5Y9aKLVJs2Ve3WTXX58khLVT75/nvVc8+NtBTFw3l3lrgPCMf0VwbQRUTaAXeo6lFMX1Io +Glo+lTyXuC14MDIy7Kv6558trHqkowu7Rbi/oLZvz/U3adeuYloIRdNXanq6xaJbtMimbdu0sUCc +Dz1UPiztopVoagNlRTg6lUOqeoOIPAx8IyLXUbwOoEA/FRG5kVydygFgrTsiBycz05y49u+3eEXR +EE7dLcLV2I8cgbFjYdgw6NoV5s6tuMrdSL9QsrMt3e7SpXDzzZY2uX59y4hZnnVZ0USk20AkCEvs +LwBVfc4JJDkLSCryotD8VH4FOqnqPhG5DBgDhMXVStWCQe7daw5dsWYyXBThaOxpaXDFFfbi+uYb +U/hWZCJlDLFvHxw6ZD5UCxZAo0bwr39Bz55lK4uH16m4xRO+FVX9UkQuBW4J4boi/VRUdb7f+fMJ +YVqtpDz9tKWjTU0tfx0KuN/YP/vMvoaHDYO//c29cmOZsnyh7N9v042PPWb3rFbNfEp27Ii+CNkV +iWOO8TqVEiMirZxRxWYROSfg8IwQiggln4o/twGfF0/KosnKsnSmH35oOpTjjnP7DtGBmy+86dNN +7zR9euxbxblJWXQqqmaV+NhjubHSzjgjvPf0CB1vpFI6HgAGAKOCHFMsB4oriEgX4Fago1tlgk0b +3Hij5TufP7/8KOWD4VZjX7HCplk+/RTaRswdNToJ9wtl0yYLlSICP/3kebhHI16nUgpUdYDzt6Qh +FUPxU0FEzgTeAC5T1T2FFVgcP5XffrPcJ5dcAi++WP4tYtxo7Hv3WljzF17wOpRghPOFsmiRJbp6 +8EF44IHy7/MTq8RCpxK1+VRE5JrCjqvqtCKKKDKfiog0AqYCfVV1XVEyhZpPZfdum3++/XYzsawI +lLax//ST6Z3+/GdLuuSRn3C9UObNs8587NjYj+Rc3omFTiWa86lcVcgxBQrtVEL0U3kcsyR71fGq +z1DVUn0jZ2VZHpQePSpOhwKla+zPPw8PP2xKyH0hZcupmITjhbJ9u8VLmzgRLr3U3bI93CcWOhW3 +cXP661a3iqIAPxVVHSAifwCXA+nA7SW9yZ49lpnx/PPNH2XkyFJKHWOUtLE/+yyMHw+//gq1apUv +3x23cfuFogq33mqpAbwOJTaoiJ1KKLnji42IXCkiD4vIE74lhGt8fiqXAqcBvUWkVcA5lwPNVLUF +cAfwekllfOopOHzYguhNmRJ9ZpeuxuIJQkka+8yZluL3q69MKZyYGPy8cMsebtyS3+0XysyZsGED +FDU74dV/ZPGX3+tUXEBEXgduwPKeCBahOJRs7Tl+KmoBKH1+Kv70AN4GUNUFQIKTabJYZGXZ9MGa +NbZEY9j1aOtUVO1l9uyzcGIR3kHl6aVQGtx+oTz/PAwZUrQRiVf/kaWidyrh+D4/X1XPFJGlqvqk +iIwiNH+SUPxUAs/Z7Oz7vajCVS3/+cGD5iHfsGHFNsEsrLH76urQITOv3r3bQqDv2+d5ZReHwuo4 +O9vq+PDh/MuRI3m3Dx60pFhbtlj+d4/YwetU3OEP5+8hJ6nWLuCEMNynSFq3NrPXvXvth1mpkjkz +nnCC6QUqMpUrQ0oKvPKK1U16unUivqVSJdOXVK9uKWPPOcdyyVSqFGnJY4dq1cyPp3nz3I7C9zcz +E6pUsXOqVrWoDccem3fdt129uqWq/uqr8m/qXt6oWtV+T8nJ9r8/cgQ++MCS/JVbShPiONiCWWjV +AnoC2zDz4KdCuO48YKbf9hBgcMA5rwM3+G2vBuoVUJ56i7d4i7d4S/GX0vQB4ryAw4KIVAWOVdUi +DU9FpBKwBgsouRX4Aeitqqv8zrkCuFtVr3TSFI9W1bAElPTw8PDwKD6uT385ncOVQBNf+SKCqr5Y +2HWh+Kmo6mcicoWI/IKZFLtlxuzh4eHh4QKuj1RE5DPgMLAMyPbtV9XSuWl6eHh4eEQ94fBTaaCq +16jqMFV90reE4T5BEZHLRGS1iPwsIoOLvqLsEZFxIvK7iCz125coIrNEZI2IfCEiCX7HhorIWhFZ +JSJdIyN1LiLSQES+EpEVIrJMRO5x9kf9M4hIVRFZICKLHflHxIrs/ohInIj8KCKfONsxI7+IrBeR +n5z/wQ/OvliSP0FEPnDkWSEi7WJFfhFp6dT7j87ffSJyj6vyh0FR/zzQ1e1yQ7x3HLl57itjee5b +RUKWIuTsCLQGlvrtexZ42FkfDIx01k8FFmNTiU2c55MIy3880NpZr4HpwlrFyjMA1Z2/lbC8PB1i +RXa/Z7gPmAh8EoPt51cgMWBfLMk/AbjVWT8GSIgl+f2eIw5LiNjQTfnDIeg1wCHMtHg/lvZ3fxlV +0nnA537b+SzIomXBOj7/TiXHkg17aa8O9gyYz0+7SMsf8CwfAZfE2jMA1TGDkFNjSXYsgvdsoDO5 +nUosyZ8G1A7YFxPyA/HAuiD7Y0L+AJm7At+4LX84pr9GYS/36qoar6o1VTU+DPcJRjAHyrBlh3SZ +ZFX9HUBVtwE+P/+CHD6jAhFpgo265mONMuqfwZk6WoyZvKeq6kpiRHaHl4CHMPNPH7EkvwKzRWSh +iNzm7IsV+ZsCO0XkTWcK6Q0RqU7syO/PDcC7zrpr8oejU9kELFenW/MoMVFffyJSA/gQuFdVD5Jf +5qh8BlXNVtWzsS/+C0SkMzEiu4hcCfyuqkuwMEgFEZXyO3RQ1XOAK4C7ReQCYqT+sWmgc4BXnGdI +x77mY0V+AESkMtAd+MDZ5Zr84fCo/xVIFZHPgSO+nVqESbFLhJToK0r5XUTqqervInI8sN3Zvxmb +8/QRFc8kIsdgHco7qvqxszumnkFV9zvWim2IHdk7AN3FfLaqATVF5B1gW4zIj6pudf7uEJGPsHBM +sVL/vwGbVHWRsz0V61RiRX4flwP/U9WdzrZr8odjpJIG/BeoAtT0W8qCnERfIlIFS/T1SRndu7gI +eb80PwH6Oeu3AB/77e8lIlVEpCnQHNMDRJrxwEpV/affvqh/BhGp47NsEZFqwJ8xRWTUyw6gqo+o +aiNVPQlr31+pal9gOjEgv4hUd0a4iMhx2Lz+MmKn/n8HNolIS2fXxcAKYkR+P3oDk/223ZPfZcVP +JeCFCCufLsOskdYCQyIpSyEyvotZXRwBNmJOnInAl47ss4BafucPxawuVhEhy7oA+TsAWZh13WLg +R6fek6L9GYAzHHkXAz8BDzr7o172IM9yIbmK+piQH9NJ+NrNMt9vNFbkd+Q5C/uAXYIlH0yIMfmr +AzuAmn77XJM/HM6P36tqe1cL9fDw8PCICcKhU1niOGR9gCmxANCic9R7eHh4eMQ44ehUjsXC3V/k +t08pIke9h4eHh0fsE9YoxR4eHh4eFYtwpBNuICL/JyLbnWWqiDRw+z4eHh4eHtFHOEyK38TM0Oo7 +y3Rnn4eHh4dHOScc1l9LVLV1Ufs8PDw8PMof4Rip7BKRPiJSyVn6YIp7D48yQ0SS/EJ8bxWR3/zC +fc8L0z1PF5HxznqyiEwXkSVOePQZ4bin370bi8iyEl77X59DoodHaQnHSKUx8DLQHrP6+g64R1U3 +unojD48QEZEngIMa5lBBIvIW8LKqLhKR14EVqvqyc+x0VV0exns3Bqar6pkluPY2ID7c9eNRMXB9 +pKKqG1S1u6rWVdVkVb3a61A8IkyewIsicsD5e6GIpIrIRyLyi4iMdEbZP4glkWrqnFdHRD4US+61 +QETOz3cDCwt0nubGhDoBixMFgK9DEZHjRORLEVnk3KO7s7+xkwTpTSdR0iQR+bOIfOtst3HOGyYi +b4vId87+2wJE8UVhfs6RdYmIDHD2Hy8ic5wR21IR6eBcMh0L+eLhUWpc81NxvgYLQlX1Kbfu5eFR +SvyH52diCcb2YnHrxqhqW7Fsln8D7gf+Cbyoqt+JSEPgCywHiz9nYyEufLwCvCcig7BYeG+qBVL8 +A7haVQ+KSG0sZYAvPl0zoKeqrhSRRUAvVe3gdDyPAn9xzjsDaIfF1FscZGrtr8BeVW3ndHbfisgs +oCcwU1VTRESwcB2oBRGsLSLHqWo6Hh6lwE3nx2CN8TisgdcGvE7FIxpZqKrbAUTkF6zDAItL1dlZ +vwQ4xXkRA9QQkeqqesivnMbAVt+Gqs5yRjqXYSHefxSR04F9QIqIdAKygfoi4stdkaaW2wUsSOGX +frI09rvXx6p6FNNffoVF+f3J73hX4AwRuc7ZjgdaYPGqxouFPf9YVf2v2Y5Fo11dSF15eBSJa52K +qo7yrYtITeBeLFDiFCxxl4dHNHLEbz3bbzub3N+HYNnuMoooK880m6ruxdr/FBGZDnTCXvB1gLNV +NVtE0rAoFKHKAnlHWkL+3BcC/E1VZ+cT0HKXXAlMEJFRqjqxkHI8PIqNqzoVx+LmaWApTjIbVR3s ++xL08IgSCktuFYxZ2EeSXSxyVpBzNmB6FN85XcRC6/s+sk7CIlInANudDqULeUcgocrVwwlFXhuL +VLww4PgXwF1iOW8QkRZiIecbOfceB4zFkk35qIefDsjDo6S4qVN5HstP/wZwhlomQA+PaKSgL/KC +9t8LvCIiP2HpHeYCdwWcswRo6bf9J+DfIpKBfbyNUdX/ich6YLpT1iIsnHiw+xc2algKpGLTyv9Q +1W2O9ZePsUATbMpNsKmtq7HpvIccmQ4ANwOISD1gp6dP8XAD10yKRcQ3XM8kyPBcyy5PvYdHRBCR +N4HXVXVBGO8xDDjgpvmvYx1WQ1VfcqtMj4qLmzqVcDhSenjEEqMwa7GwdSph4gZsJOPhUWq8KMUe +Hh4eHq7hjS48PDw8PFzD61Q8PDw8PFzD61Q8PDw8PFzD61Q8PDw8PFzD61Q8PDw8PFzD61Q8PDw8 +PFzj/wHlQqq6YUq0TwAAAABJRU5ErkJggg== +" +> +</div> + +</div> + +</div> +</div> + +</div> +<div class="cell border-box-sizing code_cell rendered"> +<div class="input"> +<div class="prompt input_prompt">In [ ]:</div> +<div class="inner_cell"> + <div class="input_area"> +<div class=" highlight hl-ipython2"><pre> +</pre></div> + +</div> +</div> +</div> + +</div> + </div> + </div> +</body> +</html> diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/XmmDoxygenLayout.xml b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/XmmDoxygenLayout.xml new file mode 100644 index 0000000000000000000000000000000000000000..66720836a11234233b612b5af8b7f44cd26b9d18 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/XmmDoxygenLayout.xml @@ -0,0 +1,184 @@ +<doxygenlayout version="1.0"> + <!-- Generated by doxygen 1.8.11 --> + <!-- Navigation index tabs for HTML output --> + <navindex> + <tab type="mainpage" visible="yes" title=""/> + <tab type="modules" visible="yes" title="" intro=""/> + <tab type="classes" visible="yes" title=""> + <tab type="classlist" visible="yes" title="" intro=""/> + <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> + <tab type="hierarchy" visible="yes" title="" intro=""/> + <tab type="classmembers" visible="yes" title="" intro=""/> + </tab> + </navindex> + + <!-- Layout definition for a class page --> + <class> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <inheritancegraph visible="$CLASS_GRAPH"/> + <collaborationgraph visible="$COLLABORATION_GRAPH"/> + <memberdecl> + <nestedclasses visible="yes" title=""/> + <publictypes title=""/> + <services title=""/> + <interfaces title=""/> + <publicslots title=""/> + <signals title=""/> + <publicmethods title=""/> + <publicstaticmethods title=""/> + <publicattributes title=""/> + <publicstaticattributes title=""/> + <protectedtypes title=""/> + <protectedslots title=""/> + <protectedmethods title=""/> + <protectedstaticmethods title=""/> + <protectedattributes title=""/> + <protectedstaticattributes title=""/> + <packagetypes title=""/> + <packagemethods title=""/> + <packagestaticmethods title=""/> + <packageattributes title=""/> + <packagestaticattributes title=""/> + <properties title=""/> + <events title=""/> + <privatetypes title=""/> + <privateslots title=""/> + <privatemethods title=""/> + <privatestaticmethods title=""/> + <privateattributes title=""/> + <privatestaticattributes title=""/> + <friends title=""/> + <related title="" subtitle=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <services title=""/> + <interfaces title=""/> + <constructors title=""/> + <functions title=""/> + <related title=""/> + <variables title=""/> + <properties title=""/> + <events title=""/> + </memberdef> + <allmemberslink visible="yes"/> + <usedfiles visible="$SHOW_USED_FILES"/> + <authorsection visible="yes"/> + </class> + + <!-- Layout definition for a namespace page --> + <namespace> + <briefdescription visible="yes"/> + <memberdecl> + <nestednamespaces visible="yes" title=""/> + <constantgroups visible="yes" title=""/> + <classes visible="yes" title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection visible="yes"/> + </namespace> + + <!-- Layout definition for a file page --> + <file> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <includegraph visible="$INCLUDE_GRAPH"/> + <includedbygraph visible="$INCLUDED_BY_GRAPH"/> + <sourcelink visible="yes"/> + <memberdecl> + <classes visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <constantgroups visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection/> + </file> + + <!-- Layout definition for a group page --> + <group> + <briefdescription visible="yes"/> + <groupgraph visible="$GROUP_GRAPHS"/> + <memberdecl> + <nestedgroups visible="yes" title=""/> + <dirs visible="yes" title=""/> + <files visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <pagedocs/> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + </memberdef> + <authorsection visible="yes"/> + </group> + + <!-- Layout definition for a directory page --> + <directory> + <briefdescription visible="yes"/> + <directorygraph visible="yes"/> + <memberdecl> + <dirs visible="yes"/> + <files visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + </directory> +</doxygenlayout> diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/footer.html b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/footer.html new file mode 100644 index 0000000000000000000000000000000000000000..62b4587cc8125f278dd33f6fb869c9d4589791ee --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/footer.html @@ -0,0 +1,3 @@ +<!-- HTML footer for doxygen 1.8.9.1--> +</body> +</html> diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/header.html b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/header.html new file mode 100644 index 0000000000000000000000000000000000000000..d66dfb6c55412ab63527611f38a3616beb9d56b1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/header.html @@ -0,0 +1,37 @@ +<!-- HTML header for doxygen 1.8.9.1--> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/> +<meta http-equiv="X-UA-Compatible" content="IE=9"/> +<meta name="generator" content="Doxygen $doxygenversion"/> +<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME--> +<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME--> +<script type="text/javascript" src="$relpath^jquery.js"></script> +<script type="text/javascript" src="$relpath^dynsections.js"></script> +<link href='http://fonts.googleapis.com/css?family=Merriweather:400,700,400italic,700italic&subset=latin,latin-ext' rel='stylesheet' type='text/css'> +<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'> +$treeview +$search +$mathjax +<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> +$extrastylesheet +</head> +<body> +<div id="top"><!-- do not remove this div, it is closed by doxygen! --> + +<!--BEGIN TITLEAREA--> +<div id="titlearea"> + <img src="$projectlogo"/> + <h1>$projectname</h1> + <nav> + <ul> + <li><a href="index.html">About</a></li> + <li><a href="GettingStarted.html">Getting Started</a></li> + <li><a href="Documentation.html">Documentation</a></li> + <li><a href="Download.html">Download</a></li> + </ul> + </nav> +</div> +<!--END TITLEAREA--> +<!-- end header part --> diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/jdoxygen.css b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/jdoxygen.css new file mode 100644 index 0000000000000000000000000000000000000000..399d2fcb0281869d9edeb14ec70f9466cc871540 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/jdoxygen.css @@ -0,0 +1,1199 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font: 400 14px/19px 'Droid Sans',sans-serif; +} + +body { + padding: 0 !important; +} + +#top { + /*border-bottom: 1px solid #A5A5A5;*/ + /*background-color: #f35757;*/ + color: #253555; +} + +#nav-path { display: none; } + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #A5A5A5; + color: #4970C0; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; + font-weight: normal; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #989898; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; + margin-bottom: 2px; + padding-bottom: 2px; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #E2E8F2; + /*border: 1px solid #A3B4D7;*/ + text-align: center; + padding-top: 5px; + padding-bottom: 5px; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #F35757; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #F35757; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 4px; + margin: 4px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +div.ah { + background-color: #989898; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin: 0 10%; + margin-bottom: 40px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: center; + padding: 20px; + background-color: #242d36; + color: #fff; + margin-top: 30px +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; + display: none; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: bold; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + background-color: #E2E8F2; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #E2E8F2; + border-left: 1px solid #E2E8F2; + border-right: 1px solid #E2E8F2; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-color: #FFFFFF; +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #C72C2C; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 5px 5px; + border-radius: 0px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view when not used as main index */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #E2E8F2; + border-spacing: 0px; +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #E2E8F2; + border-bottom: 1px solid #E2E8F2; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #E2E8F2; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + border-bottom: 1px solid #E2E8F2; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-color: #E2E8F2; + height:30px; + line-height:30px; + color:#8AA0CC; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + display: none; + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + margin: 0 auto; + border-bottom: 1px solid #C4CFE5; + width: 80%; + max-width: 1024px; +} + +div.headertitle +{ + padding: 10px 0; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname { + font-size: 32px; + margin: 0 auto; + padding: 3%; + text-align: center; + background-color: #242d36; + color: #fff; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + text-align: center; +} + +#titlearea img +{ + width: 100%; +} + +#titlearea nav +{ + padding:0 10%; + padding: 0; + text-align: center; + margin-bottom: 10px; + background-color: #f35757; +} + +#titlearea nav ul +{ + display: inline-block; + padding: 0; + margin: 0 auto; +} + +#titlearea nav ul li +{ + list-style: none; + display: inline-block; + /*float: left;*/ + /*width: 20%;*/ + padding: 10px 20px; + text-align: center; +} + +#titlearea nav ul li a +{ + color: white; + text-decoration: none; +} + +#titlearea nav ul li a:hover +{ + color: #333; + text-decoration: none; +} + +#navrow1, #navrow2 +{ + display: none; +} + +.image, +.image img +{ + text-align: center; + max-width: 100%; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +#navrow2 { + +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/jtabs.css b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/jtabs.css new file mode 100644 index 0000000000000000000000000000000000000000..8c73f31ae484873c40b7e89f702fb985a74e4e9d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/jtabs.css @@ -0,0 +1,59 @@ +.tabs, .tabs2, .tabs3 { + background-color: #F35757; + background-image: none; + width: 100%; + z-index: 101; + font-size: 13px; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; +} + +.tabs2 { + font-size: 10px; +} +.tabs3 { + font-size: 9px; +} + +.tablist { + width: 80%; + margin: 0; + padding: 0; + display: table; +} + +.tablist li { + float: left; + text-align: center; + display: table-cell; + background-color: #F35757; + line-height: 36px; + list-style: none; + width: 16%; +} + +.tablist a { + display: block; + padding: 0 30px; + font-size: 14px; + background-color: #F35757; + border-right: 1px solid #fff; + border-bottom: 1px solid #fff; + color: #FFF; + text-decoration: none; + outline: none; +} + +.tabs3 .tablist a { + padding: 0 10px; +} + +.tablist a:hover { + background-color: #B30303; + color: #fff; + text-decoration: none; +} + +.tablist li.current a { + background-color: #B30303; + color: #fff; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/python_example.py b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/python_example.py new file mode 100644 index 0000000000000000000000000000000000000000..66d7bc61faa8f17b0325a961bcfc0397c0524cfa --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/python_example.py @@ -0,0 +1,47 @@ +import numpy as np +import mhmm + +# Load Training Data +training_motion_1 = np.genfromtxt('training_motion_1.txt') +training_motion_2 = np.genfromtxt('training_motion_2.txt') +training_sound_1 = np.genfromtxt('training_sound_1.txt') +training_sound_2 = np.genfromtxt('training_sound_2.txt') + +dim_gesture = training_motion_1.shape[1] +dim_sound = training_sound_1.shape[1] + +# Create a multimodal training set +training_set = mhmm.TrainingSet(mhmm.BIMODAL) +training_set.set_dimension(dim_gesture + dim_sound) +training_set.set_dimension_input(dim_sound) + +# Record First Phrase +for frame_motion, frame_sound in zip(training_motion_1, training_sound_1): + training_set.recordPhrase_input (0, frame_motion) + training_set.recordPhrase_output(0, frame_sound) +training_set.setPhraseLabel(0, mhmm.Label('one')) + +# Record Second Phrase +for frame_motion, frame_sound in zip(training_motion_2, training_sound_2): + training_set.recordPhrase_input (1, frame_motion) + training_set.recordPhrase_output(1, frame_sound) +training_set.setPhraseLabel(1, mhmm.Label('two')) + +# Instantiate and Train a Hierarchical Multimodal HMM +xmm = mhmm.HierarchicalHMM(mhmm.BIMODAL, training_set) +xmm.set_nbStates(10) +xmm.set_nbMixtureComponents(1) +xmm.set_varianceOffset(0.1, 0.01) +xmm.train() + +# Perform joint recognition and Mapping +test_motion = np.genfromtxt('test_motion.txt') +predicted_sound = np.zeros((len(test_motion), dim_sound)) +log_likelihoods = np.zeros((len(test_motion), xmm.size())) +xmm.performance_init() +for t, frame_motion in enumerate(test_motion): + xmm.performance_update(frame) + predicted_sound[t, :] = xmm.results_predicted_output + log_likelihoods[t, :] = xmm.results_log_likelihoods + + diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_architecture.jpg b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83e4a51a6749b5d5799b54409269a4fb087c7ddb Binary files /dev/null and b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_architecture.jpg differ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_featured.jpg b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_featured.jpg new file mode 100644 index 0000000000000000000000000000000000000000..847896cbb9dcf7fbec533d43281676689cb7430c Binary files /dev/null and b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_featured.jpg differ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_featured_.jpg b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_featured_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a19876f3633036993776ca6c089ee69ee83a66ab Binary files /dev/null and b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_featured_.jpg differ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_models.jpg b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_models.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb85084419921aed938091e28c649c1dfaf987fe Binary files /dev/null and b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/doc/doc-misc/xmm_models.jpg differ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/readme.md b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..4f00e6fafe385fdb18e0c415cf6f12aed77c4255 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/readme.md @@ -0,0 +1,55 @@ +XMM — Probabilistic Models for Continuous Motion Recognition and Mapping +=========================================== + +XMM is a portable, cross-platform C++ library that implements Gaussian Mixture Models and Hidden Markov Models for recognition and regression. The XMM library was developed for movement interaction in creative applications and implements an interactive machine learning workflow with fast training and continuous, real-time inference. + +### Major Update! [Sept. 2016] + +We just updated XMM to the newest API version! + +This version is not compatible with the initial API, which is still available on a separate branch: https://github.com/Ircam-RnD/xmm/tree/v0-historic-api. + +### Contact + +Jules Francoise: <jules.francoise@ircam.fr> + +### author + +This code has been initially authored by <a href="http://julesfrancoise.com">Jules Francoise</a> during his PhD thesis, supervised by <a href="frederic-bevilacqua.net">Frederic Bevilacqua</a>, in the <a href="http://ismm.ircam.fr">Sound Music Movement Interaction</a> team of the <a href="http://www.ircam.fr/stms.html?&L=1">STMS Lab</a> - IRCAM - CNRS - UPMC (2011-2015). + +### Copyright + +Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + +### Licence + +This project is released under the <a href="http://www.gnu.org/licenses/gpl-3.0.en.html">GPLv3</a> license. +For commercial applications, a proprietary license is available upon request to Frederick Rousseau <frederick.rousseau@ircam.fr>. + +XMM is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +XMM is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with XMM. If not, see <http://www.gnu.org/licenses/>. + +### Citing this work + +If you use this code for research purposes, please cite one of the following publications: + +- J. Francoise, N. Schnell, R. Borghesi, and F. Bevilacqua, Probabilistic Models for Designing Motion and Sound Relationships. In Proceedings of the 2014 International Conference on New Interfaces for Musical Expression, NIME’14, London, UK, 2014. +- J. Francoise, N. Schnell, and F. Bevilacqua, A Multimodal Probabilistic Model for Gesture-based Control of Sound Synthesis. In Proceedings of the 21st ACM international conference on Multimedia (MM’13), Barcelona, Spain, 2013. + +### Dependencies + + The library depends on <a href="https://github.com/open-source-parsers/jsoncpp">jsoncpp</a> for JSON file I/O. The library is distributed with this softare. The units tests rely on the <a href="https://github.com/philsquared/Catch">Catch</a> testing framework + +## Documentation + +The full documentation is available on Github Pages: http://ircam-rnd.github.io/xmm/ diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmAttribute.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmAttribute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdf36553d8a8724c76ccd4ea6eeea0ad563b83bd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmAttribute.cpp @@ -0,0 +1,108 @@ +/* + * xmmAttribute.hpp + * + * Generic Attributes + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmAttribute.hpp" +#include <string> + +template <> +void xmm::checkLimits<bool>(bool const& value, bool const& limit_min, + bool const& limit_max) {} + +template <> +void xmm::checkLimits<unsigned char>(unsigned char const& value, + unsigned char const& limit_min, + unsigned char const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<char>(char const& value, char const& limit_min, + char const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<unsigned int>(unsigned int const& value, + unsigned int const& limit_min, + unsigned int const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<int>(int const& value, int const& limit_min, + int const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<long>(long const& value, long const& limit_min, + long const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<float>(float const& value, float const& limit_min, + float const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<double>(double const& value, double const& limit_min, + double const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error("Attribute value out of range. Range: [" + + std::to_string(limit_min) + " ; " + + std::to_string(limit_max) + "]"); +} + +template <> +void xmm::checkLimits<std::string>(std::string const& value, + std::string const& limit_min, + std::string const& limit_max) {} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmAttribute.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmAttribute.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d1dcfc85415954658ca3d6fc0f8bc068be445112 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmAttribute.hpp @@ -0,0 +1,644 @@ +/* + * xmmAttribute.hpp + * + * Generic Attributes + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmAttribute_h +#define xmmAttribute_h + +#include <functional> +#include <limits> +#include <stdexcept> +#include <string> +#include <vector> + +namespace xmm { + +#pragma mark - +#pragma mark === Functions checkLimits === +/** + @ingroup Common + @brief checks the validity of the requested value with respect to the current + limits + @param value requested attribute value + @param limit_min minimum value + @param limit_max maximum value + */ +template <typename T> +void checkLimits(T const& value, T const& limit_min, T const& limit_max) { + throw std::runtime_error( + "Attribute limits are not implemented for the current type."); +} + +template <> +void checkLimits<bool>(bool const& value, bool const& limit_min, + bool const& limit_max); + +template <> +void checkLimits<unsigned char>(unsigned char const& value, + unsigned char const& limit_min, + unsigned char const& limit_max); + +template <> +void checkLimits<char>(char const& value, char const& limit_min, + char const& limit_max); + +template <> +void checkLimits<unsigned int>(unsigned int const& value, + unsigned int const& limit_min, + unsigned int const& limit_max); + +template <> +void checkLimits<int>(int const& value, int const& limit_min, + int const& limit_max); + +template <> +void checkLimits<long>(long const& value, long const& limit_min, + long const& limit_max); + +template <> +void checkLimits<float>(float const& value, float const& limit_min, + float const& limit_max); + +template <> +void checkLimits<double>(double const& value, double const& limit_min, + double const& limit_max); + +template <> +void checkLimits<std::string>(std::string const& value, + std::string const& limit_min, + std::string const& limit_max); + +#pragma mark - +#pragma mark === Class AttributeBase === +/** + @ingroup Common + @brief Base Class for Generic Attributes + */ +class AttributeBase { + public: + virtual ~AttributeBase() {} + + /** + @brief Default Constructor + */ + AttributeBase() : changed(false) {} + + /** + @brief Defines if the value has been changed + */ + bool changed; +}; + +#pragma mark - +#pragma mark === Class Attribute === +/** + @ingroup Common + @brief Generic Attribute + @tparam T attribute type + */ +template <typename T> +class Attribute : public AttributeBase { + public: + typedef std::function<void(AttributeBase*)> AttributeChangeCallback; + + template <typename U, typename args, class ListenerClass> + void onAttributeChange(U* owner, + void (ListenerClass::*listenerMethod)(args)) { + using namespace std::placeholders; + if (owner) + callback_ = std::bind(listenerMethod, owner, _1); + else + callback_ = nullptr; + } + + /** + @brief Default Constructor + @param value attribute value + @param limit_min minimum limit + @param limit_max maximum limit + */ + Attribute(T const& value = T(), T const& limit_min = defaultLimitMin(), + T const& limit_max = defaultLimitMax()) + : limit_min_(limit_min), limit_max_(limit_max) { + set(value, true); + changed = false; + } + + /** + @brief Copy Constructor + @param src source attribute + @warning the listener object is not copied from the source attribute + */ + Attribute(Attribute const& src) + : value_(src.value_), + limit_min_(src.limit_min_), + limit_max_(src.limit_max_) { + changed = false; + } + + /** + @brief Assignment operator + @param src source attribute + @return copy of the source Attribute object + @warning the listener object is not copied from the source attribute + */ + template <typename U> + Attribute& operator=(Attribute<U> const& src) { + if (this != &src) { + value_ = src.value_; + limit_min_ = src.limit_min_; + limit_max_ = src.limit_max_; + changed = false; + } + return *this; + } + + /** + @brief Set the attribute value + @param value requested value + @param silently if true, don't notify the listener object + @throws domain_error exception if the value exceeds the limits + @throws runtime_error exception if the limit checking are not implemented + for the current type + */ + void set(T const& value, bool silently = false) { + checkLimits(value, limit_min_, limit_max_); + value_ = value; + changed = true; + if (!silently && callback_) callback_(this); + } + + /** + @brief get the attribute's current value + @return the attribute's current value + */ + T get() const { return value_; } + + /** + @brief set the attribute's minimum value + @param limit_min minimum value + */ + void setLimitMin(T const& limit_min = defaultLimitMin()) { + limit_min_ = limit_min; + } + + /** + @brief set the attribute's maximum value + @param limit_max maximum value + */ + void setLimitMax(T const& limit_max = defaultLimitMax()) { + limit_max_ = limit_max; + } + + /** + @brief set the attribute's limit values + @param limit_min minimum value + @param limit_max maximum value + */ + void setLimits(T const& limit_min = defaultLimitMin(), + T const& limit_max = defaultLimitMax()) { + setLimitMin(limit_min); + setLimitMax(limit_max); + } + + protected: + /** + @brief Attribute default minimum value + */ + static T defaultLimitMin() { return std::numeric_limits<T>::lowest(); } + + /** + @brief Attribute default maximum value + */ + static T defaultLimitMax() { return std::numeric_limits<T>::max(); } + + /** + @brief Current value of the attribute + */ + T value_; + + /** + @brief Minimum value of the attribute + */ + T limit_min_; + + /** + @brief Maximum value of the attribute + */ + T limit_max_; + + /** + @brief Callback function to be called on attribute change + */ + AttributeChangeCallback callback_; +}; + +#pragma mark - +#pragma mark === Class Attribute: vector specialization === +/** + @ingroup Common + @brief Generic Attribute (Vector Specialization) + @tparam T Vector base type + */ +template <typename T> +class Attribute<std::vector<T>> : public AttributeBase { + public: + typedef std::function<void(AttributeBase*)> AttributeChangeCallback; + + template <typename U, typename args, class ListenerClass> + void onAttributeChange(U* owner, + void (ListenerClass::*listenerMethod)(args)) { + using namespace std::placeholders; + if (owner) + callback_ = std::bind(listenerMethod, owner, _1); + else + callback_ = nullptr; + } + + /** + @brief Default Constructor + @param value attribute value + @param limit_min minimum limit + @param limit_max maximum limit + @param size size of the vector attribute (if 0, no size checking on set) + */ + Attribute(std::vector<T> const& value = std::vector<T>(), + T const& limit_min = defaultLimitMin(), + T const& limit_max = defaultLimitMax(), unsigned int size = 0) + : limit_min_(limit_min), limit_max_(limit_max), size_(size) { + set(value, true); + changed = false; + } + + /** + @brief Copy Constructor + @param src source attribute + @warning the listener object is not copied from the source attribute + */ + Attribute(Attribute const& src) + : value_(src.value_), + limit_min_(src.limit_min_), + limit_max_(src.limit_max_), + size_(src.size_) { + changed = false; + } + + /** + @brief Assignment operator + @param src source attribute + @return copy of the source Attribute object + @warning the listener object is not copied from the source attribute + */ + template <typename U> + Attribute& operator=(Attribute<U> const& src) { + if (this != &src) { + value_ = src.value_; + limit_min_ = src.limit_min_; + limit_max_ = src.limit_max_; + size_ = src.size_; + changed = false; + } + return *this; + } + + /** + @brief Set the attribute value + @param value requested value + @param silently if true, don't notify the listener object + @throws domain_error exception if the value exceeds the limits, or if the + value does not + match the attribute's size (if the attribute's size is > 0) + @throws runtime_error exception if the limit checking are not implemented + for the current type + */ + void set(std::vector<T> const& value, bool silently = false) { + if (size_ > 0 && value.size() != size_) { + throw std::domain_error("Attribute value has the wrong size"); + } + for (auto& val : value) { + checkLimits(val, limit_min_, limit_max_); + } + value_ = value; + changed = true; + if (!silently && callback_) callback_(this); + } + + /** + @brief get the attribute's current value + @return the attribute's current value + */ + std::vector<T> get() const { return value_; } + + /** + @brief get the attribute's current value at a given index + @param index index in the value vector + @return the attribute's current value at a given index + */ + T at(unsigned int index) const { + if (index < size_) { + return value_[index]; + } else { + throw std::out_of_range("Index out of range"); + } + } + + /** + @brief set the attribute's minimum value + @param limit_min minimum value + */ + void setLimitMin(T const& limit_min = defaultLimitMin()) { + limit_min_ = limit_min; + } + + /** + @brief set the attribute's maximum value + @param limit_max maximum value + */ + void setLimitMax(T const& limit_max = defaultLimitMax()) { + limit_max_ = limit_max; + } + + /** + @brief set the attribute's limit values + @param limit_min minimum value + @param limit_max maximum value + */ + void setLimits(T const& limit_min = defaultLimitMin(), + T const& limit_max = defaultLimitMax()) { + setLimitMin(limit_min); + setLimitMax(limit_max); + } + + /** + @brief set the attribute's size (vector Attribute). if 0, there is not + size-checking on set. + @param size vector size + */ + void resize(unsigned int size) { + value_.resize(size, T()); + size_ = size; + } + + /** + @brief get the attribute's current size (vector Attribute) + @return value vector size + */ + unsigned int size() const { return value_.size(); } + + protected: + /** + @brief Attribute default minimum value + */ + static T defaultLimitMin() { return std::numeric_limits<T>::lowest(); } + + /** + @brief Attribute default maximum value + */ + static T defaultLimitMax() { return std::numeric_limits<T>::max(); } + + /** + @brief Current value of the attribute + */ + std::vector<T> value_; + + /** + @brief Minimum value of the attribute + */ + T limit_min_; + + /** + @brief Maximum value of the attribute + */ + T limit_max_; + + /** + @brief Size of the vector of values + */ + unsigned int size_; + + /** + @brief Callback function to be called on attribute change + */ + AttributeChangeCallback callback_; +}; + +#pragma mark - +#pragma mark === Class Attribute: vector<string> specialization === +/** + @ingroup Common + @brief Generic Attribute (Vector Specialization) + */ +template <> +class Attribute<std::vector<std::string>> : public AttributeBase { + public: + typedef std::function<void(AttributeBase*)> AttributeChangeCallback; + + template <typename U, typename args, class ListenerClass> + void onAttributeChange(U* owner, + void (ListenerClass::*listenerMethod)(args)) { + using namespace std::placeholders; + if (owner) + callback_ = std::bind(listenerMethod, owner, _1); + else + callback_ = nullptr; + } + + /** + @brief Default Constructor + @param value attribute value + @param limit_min minimum limit + @param limit_max maximum limit + @param size size of the vector attribute (if 0, no size checking on set) + */ + Attribute(std::vector<std::string> const& value = {}, + std::string const& limit_min = "", + std::string const& limit_max = "", unsigned int size = 0) + : limit_min_(limit_min), limit_max_(limit_max), size_(size) { + set(value, true); + changed = false; + } + + /** + @brief Copy Constructor + @param src source attribute + @warning the listener object is not copied from the source attribute + */ + Attribute(Attribute const& src) + : value_(src.value_), + limit_min_(src.limit_min_), + limit_max_(src.limit_max_), + size_(src.size_) { + changed = false; + } + + /** + @brief Assignment operator + @param src source attribute + @return copy of the source Attribute object + @warning the listener object is not copied from the source attribute + */ + template <typename U> + Attribute& operator=(Attribute<U> const& src) { + if (this != &src) { + value_ = src.value_; + limit_min_ = src.limit_min_; + limit_max_ = src.limit_max_; + size_ = src.size_; + changed = false; + } + return *this; + } + + /** + @brief Set the attribute value + @param value requested value + @param silently if true, don't notify the listener object + @throws domain_error exception if the value exceeds the limits, or if the + value does not + match the attribute's size (if the attribute's size is > 0) + @throws runtime_error exception if the limit checking are not implemented + for the current type + */ + void set(std::vector<std::string> const& value, bool silently = false) { + if (size_ > 0 && value.size() != size_) { + throw std::domain_error("Attribute value has the wrong size"); + } + for (auto& val : value) { + checkLimits(val, limit_min_, limit_max_); + } + value_ = value; + changed = true; + if (!silently && callback_) callback_(this); + } + + /** + @brief get the attribute's current value + @return the attribute's current value + */ + std::vector<std::string> get() const { return value_; } + + /** + @brief get the attribute's current value at a given index + @param index index in the value vector + @return the attribute's current value at a given index + */ + std::string at(unsigned int index) const { + if (index < size_) { + return value_[index]; + } else { + throw std::out_of_range("Index out of range"); + } + } + + /** + @brief set the attribute's minimum value + @param limit_min minimum value + */ + void setLimitMin(std::string const& limit_min = defaultLimitMin()) { + limit_min_ = limit_min; + } + + /** + @brief set the attribute's maximum value + @param limit_max maximum value + */ + void setLimitMax(std::string const& limit_max = defaultLimitMax()) { + limit_max_ = limit_max; + } + + /** + @brief set the attribute's limit values + @param limit_min minimum value + @param limit_max maximum value + */ + void setLimits(std::string const& limit_min = defaultLimitMin(), + std::string const& limit_max = defaultLimitMax()) { + setLimitMin(limit_min); + setLimitMax(limit_max); + } + + /** + @brief set the attribute's size (vector Attribute). if 0, there is not + size-checking on set. + @param size vector size + */ + void resize(unsigned int size) { + value_.resize(size, ""); + size_ = size; + } + + /** + @brief get the attribute's current size (vector Attribute) + @return value vector size + */ + unsigned int size() const { + return static_cast<unsigned int>(value_.size()); + } + + protected: + /** + @brief Attribute default minimum value + */ + static std::string defaultLimitMin() { return ""; } + + /** + @brief Attribute default maximum value + */ + static std::string defaultLimitMax() { return ""; } + + /** + @brief Current value of the attribute + */ + std::vector<std::string> value_; + + /** + @brief Minimum value of the attribute + */ + std::string limit_min_; + + /** + @brief Maximum value of the attribute + */ + std::string limit_max_; + + /** + @brief Size of the vector of values + */ + unsigned int size_; + + /** + @brief Callback function to be called on attribute change + */ + AttributeChangeCallback callback_; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmCircularbuffer.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmCircularbuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c4357611e365ff8f7eed6ba890644769d27da78d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmCircularbuffer.hpp @@ -0,0 +1,195 @@ +/* + * xmmCircularBuffer.hpp + * + * Simple Circular Buffer Utility + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmCircularbuffer_h +#define xmmCircularbuffer_h + +#include <exception> +#include <stdexcept> +#include <vector> + +namespace xmm { +/** + @ingroup Common + @brief Simple CircularBuffer Class + @details Multichannel Circular Buffer + @tparam T Data type + @tparam channels number of channels + */ +template <typename T, unsigned int channels = 1> +class CircularBuffer { + public: + /** + @brief Constructor + @param length length of the CircularBuffer + */ + CircularBuffer(unsigned int length = 1) { + length_ = length; + for (int c = 0; c < channels; c++) { + data_[c].resize(length_); + } + current_index_ = 0; + full_ = false; + } + + /** + @brief Access data by index & channel + @return value at the given index and channel + */ + T operator()(unsigned int channel, unsigned int index) const { + if (channel >= channels) + throw std::out_of_range("CircularBuffer: channel out of bounds"); + unsigned int m = full_ ? length_ : current_index_; + if (index >= m) + throw std::out_of_range("CircularBuffer: index out of bounds"); + return data_[channel][index]; + } + + /** + @brief Clear the content of the buffer + */ + void clear() { + current_index_ = 0; + full_ = false; + } + + /** + @brief Add an element to the buffer (single-channel method) + @param value element to add to the buffer + @throws invalid_argument if the buffer is multi-channel + */ + void push(T const value) { + if (channels > 1) + throw std::invalid_argument("You must pass a vector or array"); + data_[0][current_index_] = value; + current_index_++; + if (current_index_ == length_) full_ = true; + current_index_ %= length_; + } + + /** + @brief Add an element to the buffer (multi-channel method) + @param value element to add to the buffer + */ + void push(T const *value) { + for (int c = 0; c < channels; c++) { + data_[c][current_index_] = value[c]; + } + current_index_++; + if (current_index_ == length_) full_ = true; + current_index_ %= length_; + } + + /** + @brief Add an element to the buffer (multi-channel method) + @param value element to add to the buffer + */ + void push(std::vector<T> const &value) { + for (int c = 0; c < channels; c++) { + data_[c][current_index_] = value[c]; + } + current_index_++; + if (current_index_ == length_) full_ = true; + current_index_ %= length_; + } + + /** + @brief Get the size of the CircularBuffer + @return size of the CircularBuffer (length) + */ + unsigned int size() const { return length_; } + + /** + @brief Get the actual size of the CircularBuffer (< size() if the buffer is + not full) + @return actual size of the CircularBuffer (length) + */ + unsigned int size_t() const { return (full_ ? length_ : current_index_); } + + /** + @brief Resize the buffer to a specific length + @param length target length of the CircularBuffer + */ + void resize(unsigned int length) { + if (length == length_) return; + if (length > length_) { + full_ = false; + } else if (current_index_ >= length) { + full_ = true; + current_index_ = 0; + } + length_ = length; + for (int c = 0; c < channels; c++) { + data_[c].resize(length_); + } + } + + /** + @brief Compute the mean of the buffer + @return vector containing the mean of the buffer + */ + std::vector<T> mean() const { + std::vector<T> _mean(channels, 0.0); + int size = full_ ? length_ : current_index_; + for (int c = 0; c < channels; c++) { + for (int i = 0; i < size; i++) { + _mean[c] += data_[c][i]; + } + _mean[c] /= T(size); + } + return _mean; + } + + protected: + /** + @brief buffer data + */ + std::vector<T> data_[channels]; + + /** + @brief length of the buffer + */ + unsigned int length_; + + /** + @brief current index in the buffer + */ + unsigned int current_index_; + + /** + @brief Defines if the CircularBuffer is already full + */ + bool full_; +}; +} + +#endif \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmEvents.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmEvents.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6468eb7bea3aaafd3480d3bc8855a4a02d5f2291 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmEvents.hpp @@ -0,0 +1,113 @@ +/* + * xmmEvents.hpp + * + * Template classes for Event generators + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmEvents_h +#define xmmEvents_h + +#include <functional> +#include <map> +#include <set> + +namespace xmm { +/** + @ingroup Common + @brief Generator class for a specific type of events + @tparam EventType Type of Events that can be sent + */ +template <typename EventType> +class EventGenerator { + public: + typedef std::function<void(EventType&)> EventCallBack; + + /** + @brief Default constructor + */ + EventGenerator() {} + + /** + @brief Destructor + @details Also notifies all listeners that this generators is deleted + */ + virtual ~EventGenerator() {} + + /** + @brief Adds a listener object to be notified when events are sent + @param owner Pointer to the listener object + @param listenerMethod Method to be called in the target class + @tparam U type of the target object + @tparam args callback arguments + @tparam ListenerClass Listener Class + */ + template <typename U, typename args, class ListenerClass> + void addListener(U* owner, void (ListenerClass::*listenerMethod)(args)) { + callbacks_.insert(std::pair<void*, EventCallBack>( + static_cast<void*>(owner), + std::bind(listenerMethod, owner, std::placeholders::_1))); + } + + /** + @brief Removes a listener object + @param owner Pointer to the listener object + @param listenerMethod Method to be called in the target class + @tparam U type of the target object + @tparam args callback arguments + @tparam ListenerClass Listener Class + */ + template <typename U, typename args, class ListenerClass> + void removeListener(U* owner, void (ListenerClass::*listenerMethod)(args)) { + callbacks_.erase(static_cast<void*>(owner)); + } + + /** + @brief Removes all listeners + */ + void removeListeners() { callbacks_.clear(); } + + /** + @brief Propagates the event to all listeners + @param e event + */ + void notifyListeners(EventType& e) const { + for (auto& callback : callbacks_) { + callback.second(e); + } + } + + private: + /** + @brief Set of listener objects + */ + std::map<void*, EventCallBack> callbacks_; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmJson.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmJson.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96d864bd36bc891995027be8ecc5ea68dd3dd6b4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmJson.cpp @@ -0,0 +1,133 @@ +/* + * xmmJson.cpp + * + * Set of utility functions for JSON I/O + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmJson.hpp" + +template <> +void xmm::json2array(Json::Value const& root, float* a, unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asFloat(); + } +} + +template <> +void xmm::json2array(Json::Value const& root, double* a, unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asDouble(); + } +} + +template <> +void xmm::json2array(Json::Value const& root, bool* a, unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asBool(); + } +} + +template <> +void xmm::json2array(Json::Value const& root, std::string* a, unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asString(); + } +} + +template <> +void xmm::json2vector(Json::Value const& root, std::vector<float>& a, + unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asFloat(); + } +} + +template <> +void xmm::json2vector(Json::Value const& root, std::vector<double>& a, + unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asDouble(); + } +} + +template <> +void xmm::json2vector(Json::Value const& root, std::vector<bool>& a, + unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asBool(); + } +} + +template <> +void xmm::json2vector(Json::Value const& root, std::vector<std::string>& a, + unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asString(); + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmJson.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmJson.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8a27eeef8fc478b0e9311a737f82733bacc8333f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmJson.hpp @@ -0,0 +1,323 @@ +/* + * xmmJson.hpp + * + * Set of utility functions for JSON I/O + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmJson_h +#define xmmJson_h + +#include "../../../dependencies/jsoncpp/include/json.h" +#include <fstream> +#include <vector> + +namespace xmm { +/** + @ingroup Common + @brief Abstract class for handling JSON + File I/O + @details the JSON I/O methods need to be implemented. writeFile and readFile + methods + can be used in Python for file I/O. The __str__() Python method is implemented + to use + with "print" in Python. It return the pretty-printed JSON String. + */ +class Writable { + public: + virtual ~Writable() {} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const = 0; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root) = 0; + +///@} + +#ifdef SWIGPYTHON + /** @name Python File I/O */ + ///@{ + + /** + @brief write method for python wrapping ('write' keyword forbidden, name + has to be different) + @warning only defined if SWIGPYTHON is defined + */ + void writeFile(char* fileName) const { + std::ofstream outStream; + outStream.open(fileName); + outStream << this->toJson(); + outStream.close(); + } + + /** + @brief read method for python wrapping ('read' keyword forbidden, name has + to be different) + @warning only defined if SWIGPYTHON is defined + */ + void readFile(char* fileName) { + std::string jsonstring; + std::ifstream inStream; + inStream.open(fileName); + // inStream.seekg(0, std::ios::end); + // jsonstring.reserve(inStream.tellg()); + // inStream.seekg(0, std::ios::beg); + // + // jsonstring.assign((std::istreambuf_iterator<char>(inStream)), + // std::istreambuf_iterator<char>()); + Json::Value root; + Json::Reader reader; + if (reader.parse(inStream, root)) { + this->fromJson(root); + } else { + throw std::runtime_error("Cannot Parse Json File"); + } + inStream.close(); + } + + /** + @brief "print" method for python => returns the results of write method + @warning only defined if SWIGPYTHON is defined + */ + std::string __str__() const { return this->toJson().toStyledString(); } + +///@} +#endif +}; + +/** + @ingroup Common + @brief Exception class for handling JSON parsing errors + */ +class JsonException : public std::exception { + public: + /** + @brief Type of Json parsing errors + */ + enum class JsonErrorType { + /** + @brief A Node is Missing in the Json Value + */ + JsonMissingNode, + + /** + @brief The current node has wrong data type + */ + JsonTypeError, + + /** + @brief The current node has an inadmissible value + */ + JsonValueError + }; + + /** + @brief Default Constructor + @param errorType type of parsing error + @param nodename name of the JSON node where the error occurred + */ + JsonException(JsonErrorType errorType, std::string nodename = "") + : errorType_(errorType) { + nodename_.push_back(nodename); + } + + /** + @brief Constructor From exception message + @param src Source Exception + @param nodename name of the + */ + explicit JsonException(JsonException const& src, std::string nodename) + : errorType_(src.errorType_), nodename_(src.nodename_) { + nodename_.push_back(nodename); + } + + /** + @brief Copy Constructor + @param src Source exception + */ + JsonException(JsonException const& src) + : errorType_(src.errorType_), nodename_(src.nodename_) {} + + /** + @brief Assigment + @param src Source exception + */ + JsonException& operator=(JsonException const& src) { + if (this != &src) { + errorType_ = src.errorType_; + nodename_ = src.nodename_; + } + return *this; + } + + /** + @brief Get exception message + @return exception message + */ + virtual const char* what() const throw() { + std::string message; + switch (errorType_) { + case JsonErrorType::JsonMissingNode: + message = "Json Structure Error: Missing Node"; + break; + + case JsonErrorType::JsonTypeError: + message = "Json Structure Error: Type Error"; + break; + + case JsonErrorType::JsonValueError: + message = "Json Structure Error: Value Error"; + break; + + default: + message = "Json unknown error type"; + break; + } + message += " (root"; + for (auto& node : nodename_) message += " > " + node; + message += ")"; + return message.c_str(); + } + + private: + /** + @brief Type of Json Parsing Error + */ + JsonErrorType errorType_; + + /** + @brief Name of the Json Node presenting an error + */ + std::vector<std::string> nodename_; +}; + +/** + @ingroup Common + @brief Writes a C-style array to a Json Value + @param a array + @param n array size + @return Json Value containing the array in Json Format + */ +template <typename T> +Json::Value array2json(T const* a, unsigned int n) { + Json::Value root; + root.resize(static_cast<Json::ArrayIndex>(n)); + for (int i = 0; i < n; i++) { + root[i] = a[i]; + } + return root; +} + +/** + @ingroup Common + @brief Reads a C-style array from a Json Value + @param root Json Value containing the array in Json Format + @param a array + @param n array size + */ +template <typename T> +void json2array(Json::Value const& root, T* a, unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asInt(); + } +} + +template <> +void json2array(Json::Value const& root, float* a, unsigned int n); +template <> +void json2array(Json::Value const& root, double* a, unsigned int n); +template <> +void json2array(Json::Value const& root, bool* a, unsigned int n); +template <> +void json2array(Json::Value const& root, std::string* a, unsigned int n); + +/** + @ingroup Common + @brief Writes a vector to a Json Value + @param a vector + @return Json Value containing the vector data in Json Format + */ +template <typename T> +Json::Value vector2json(std::vector<T> const& a) { + Json::Value root; + root.resize(static_cast<Json::ArrayIndex>(a.size())); + for (int i = 0; i < a.size(); i++) { + root[i] = a[i]; + } + return root; +} + +/** + @ingroup Common + @brief Reads a vector from a Json Value + @param root Json Value containing the vector data in Json Format + @param a vector + @param n vector size + @warning the target vector must already have the appropriate size + */ +template <typename T> +void json2vector(Json::Value const& root, std::vector<T>& a, unsigned int n) { + if (!root.isArray()) + throw JsonException(JsonException::JsonErrorType::JsonTypeError); + if (root.size() != n) + throw JsonException(JsonException::JsonErrorType::JsonValueError); + unsigned int i = 0; + for (auto it : root) { + a[i++] = it.asInt(); + } +} + +template <> +void json2vector(Json::Value const& root, std::vector<float>& a, + unsigned int n); +template <> +void json2vector(Json::Value const& root, std::vector<double>& a, + unsigned int n); +template <> +void json2vector(Json::Value const& root, std::vector<bool>& a, unsigned int n); +template <> +void json2vector(Json::Value const& root, std::vector<std::string>& a, + unsigned int n); +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmMatrix.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmMatrix.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b9611ebb73586754ddc7b292378405fb1d4d0c36 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/common/xmmMatrix.hpp @@ -0,0 +1,359 @@ +/* + * xmmMatrix.hpp + * + * Matrix Utilities + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmMatrix_h +#define xmmMatrix_h + +#include <cmath> +#include <exception> +#include <iostream> +#include <stdexcept> +#include <vector> + +namespace xmm { +/** + @defgroup Common [Core] Common Classes and Utilities + */ + +/** + @ingroup Common + @brief Dirty and very incomplete Matrix Class + @details Contains few utilities for matrix operations, with possibility to + share data with vectors + @tparam T data type of the matrix (should be used with float/double) + */ +template <typename T> +class Matrix { + public: + /** + @brief Epsilon value for Matrix inversion + @details defines + */ + static const double kEpsilonPseudoInverse() { return 1.0e-9; } + + /** + @brief number of rows of the matrix + */ + unsigned int nrows; + + /** + @brief number of columns of the matrix + */ + unsigned int ncols; + + /** + @brief Matrix Data if not shared + */ + std::vector<T> _data; + + /** + @brief Data iterator + @details Can point to own data vector, or can be shared with another + container. + */ + typename std::vector<T>::iterator data; + + /** + @brief Defines if the matrix has its own data + */ + bool ownData; + + /** + @brief Default Constructor + @param ownData_ defines if the matrix stores the data itself (true by + default) + */ + Matrix(bool ownData_ = true) : nrows(0), ncols(0), ownData(ownData_) {} + + /** + @brief Square Matrix Constructor + @param nrows_ Number of rows (defines a square matrix) + @param ownData_ defines if the matrix stores the data itself (true by + default) + */ + Matrix(unsigned int nrows_, bool ownData_ = true) { + nrows = nrows_; + ncols = nrows_; + ownData = ownData_; + if (ownData) { + _data.assign(nrows * ncols, T(0.0)); + data = _data.begin(); + } + } + + /** + @brief Constructor + @param nrows_ Number of rows + @param ncols_ Number of columns + @param ownData_ defines if the matrix stores the data itself (true by + default) + */ + Matrix(unsigned int nrows_, unsigned int ncols_, bool ownData_ = true) { + nrows = nrows_; + ncols = ncols_; + ownData = ownData_; + if (ownData) { + _data.assign(nrows * ncols, T(0.0)); + data = _data.begin(); + } + } + + /** + @brief Constructor from vector (shared data) + @param nrows_ Number of rows + @param ncols_ Number of columns + @param data_it iterator to the vector data + */ + Matrix(unsigned int nrows_, unsigned int ncols_, + typename std::vector<T>::iterator data_it) { + nrows = nrows_; + ncols = ncols_; + ownData = false; + data = data_it; + } + + /** + @brief Resize the matrix + @param nrows_ Number of rows + @param ncols_ Number of columns + @throws runtime_error if the matrix is not square + */ + void resize(unsigned int nrows_, unsigned int ncols_) { + nrows = nrows_; + ncols = ncols_; + _data.resize(nrows * ncols); + } + + /** + @brief Resize a Square Matrix + @param nrows_ Number of rows + */ + void resize(unsigned int nrows_) { + if (nrows != ncols) throw std::runtime_error("Matrix is not square"); + + nrows = nrows_; + ncols = nrows; + _data.resize(nrows * ncols); + } + + /** + @brief Compute the Sum of the matrix + @return sum of all elements in the matrix + */ + float sum() const { + float sum_(0.); + for (unsigned int i = 0; i < nrows * ncols; i++) sum_ += data[i]; + return sum_; + } + + /** + @brief Print the matrix + */ + void print() const { + for (unsigned int i = 0; i < nrows; i++) { + for (unsigned int j = 0; j < ncols; j++) { + std::cout << data[i * ncols + j] << " "; + } + std::cout << std::endl; + } + } + + /** + @brief Compute the transpose matrix + @return pointer to the transpose Matrix + @warning Memory is allocated for the new matrix (need to be freed) + */ + Matrix<T> *transpose() const { + Matrix<T> *out = new Matrix<T>(ncols, nrows); + for (unsigned int i = 0; i < ncols; i++) { + for (unsigned int j = 0; j < nrows; j++) { + out->data[i * nrows + j] = data[j * ncols + i]; + } + } + return out; + } + + /** + @brief Compute the product of matrices + @return pointer to the Matrix resulting of the product + @warning Memory is allocated for the new matrix (need to be freed) + @throws runtime_error if the matrices have wrong dimensions + */ + Matrix<T> *product(Matrix const *mat) const { + if (ncols != mat->nrows) + throw std::runtime_error("Wrong dimensions for matrix product"); + + Matrix<T> *out = new Matrix<T>(nrows, mat->ncols); + for (unsigned int i = 0; i < nrows; i++) { + for (unsigned int j = 0; j < mat->ncols; j++) { + out->data[i * mat->ncols + j] = 0.; + for (unsigned int k = 0; k < ncols; k++) { + out->data[i * mat->ncols + j] += + data[i * ncols + k] * mat->data[k * mat->ncols + j]; + } + } + } + return out; + } + + /** + @brief Compute the Pseudo-Inverse of a Matrix + @param det Determinant (computed with the inversion) + @return pointer to the inverse Matrix + @warning Memory is allocated for the new matrix (need to be freed) + */ + Matrix<T> *pinv(double *det) const { + Matrix<T> *inverse = NULL; + if (nrows == ncols) { + inverse = gauss_jordan_inverse(det); + if (inverse) { + return inverse; + } + } + + inverse = new Matrix<T>(ncols, nrows); + Matrix<T> *transp, *prod, *dst; + transp = this->transpose(); + if (nrows >= ncols) { + prod = transp->product(this); + dst = prod->gauss_jordan_inverse(det); + inverse = dst->product(transp); + } else { + prod = this->product(transp); + dst = prod->gauss_jordan_inverse(det); + inverse = transp->product(dst); + } + *det = 0; + delete transp; + delete prod; + delete dst; + return inverse; + } + + /** + @brief Compute the Gauss-Jordan Inverse of a Square Matrix + @param det Determinant (computed with the inversion) + @return pointer to the inverse Matrix + @warning Memory is allocated for the new matrix (need to be freed) + @throws runtime_error if the matrix is not square + @throws runtime_error if the matrix is not invertible + */ + Matrix<T> *gauss_jordan_inverse(double *det) const { + if (nrows != ncols) { + throw std::runtime_error( + "Gauss-Jordan inversion: Can't invert Non-square matrix"); + } + *det = 1.0f; + Matrix<T> mat(nrows, ncols * 2); + Matrix<T> new_mat(nrows, ncols * 2); + + unsigned int n = nrows; + + // Create matrix + for (unsigned int i = 0; i < n; i++) { + for (unsigned int j = 0; j < n; j++) { + mat._data[i * 2 * n + j] = data[i * n + j]; + } + mat._data[i * 2 * n + n + i] = 1; + } + + for (unsigned int k = 0; k < n; k++) { + unsigned int i(k); + while (std::fabs(mat._data[i * 2 * n + k]) < + kEpsilonPseudoInverse()) { + i++; + if (i == n) { + throw std::runtime_error("Non-invertible matrix"); + } + } + *det *= mat._data[i * 2 * n + k]; + + // if found > Exchange lines + if (i != k) { + mat.swap_lines(i, k); + } + + new_mat._data = mat._data; + + for (unsigned int j = 0; j < 2 * n; j++) { + new_mat._data[k * 2 * n + j] /= mat._data[k * 2 * n + k]; + } + for (i = 0; i < n; i++) { + if (i != k) { + for (unsigned int j = 0; j < 2 * n; j++) { + new_mat._data[i * 2 * n + j] -= + mat._data[i * 2 * n + k] * + new_mat._data[k * 2 * n + j]; + } + } + } + mat._data = new_mat._data; + } + + Matrix<T> *dst = new Matrix<T>(nrows, ncols); + for (unsigned int i = 0; i < n; i++) + for (unsigned int j = 0; j < n; j++) + dst->_data[i * n + j] = mat._data[i * 2 * n + n + j]; + return dst; + } + + /** + @brief Swap 2 lines of the matrix + @param i index of the first line + @param j index of the second line + */ + void swap_lines(unsigned int i, unsigned int j) { + T tmp; + for (unsigned int k = 0; k < ncols; k++) { + tmp = data[i * ncols + k]; + data[i * ncols + k] = data[j * ncols + k]; + data[j * ncols + k] = tmp; + } + } + + /** + @brief Swap 2 columns of the matrix + @param i index of the first column + @param j index of the second column + */ + void swap_columns(unsigned int i, unsigned int j) { + T tmp; + for (unsigned int k = 0; k < nrows; k++) { + tmp = data[k * ncols + i]; + data[k * ncols + i] = data[k * ncols + j]; + data[k * ncols + j] = tmp; + } + } +}; +} + +#endif \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/distributions/xmmGaussianDistribution.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/distributions/xmmGaussianDistribution.cpp new file mode 100644 index 0000000000000000000000000000000000000000..475f0a560f02d87238fe1e66f25d9e465ca8c2c1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/distributions/xmmGaussianDistribution.cpp @@ -0,0 +1,717 @@ +/* + * xmmGaussianDistribution.cpp + * + * Multivariate Gaussian Distribution + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "../common/xmmMatrix.hpp" +#include "xmmGaussianDistribution.hpp" +#include <algorithm> +#include <math.h> + +#ifdef WIN32 + +#define M_PI 3.14159265358979323846264338328 /**< pi */ +//#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#pragma mark Constructors +xmm::GaussianDistribution::GaussianDistribution(bool bimodal, + unsigned int dimension_, + unsigned int dimension_input_, + CovarianceMode covariance_mode_) + : dimension(dimension_, (bimodal) ? 2 : 1), + dimension_input(dimension_input_, 0, (bimodal) ? dimension_ - 1 : 0), + covariance_mode(covariance_mode_), + bimodal_(bimodal), + covariance_determinant_(0.), + covariance_determinant_input_(0.) { + dimension.onAttributeChange(this, + &xmm::GaussianDistribution::onAttributeChange); + dimension_input.onAttributeChange( + this, &xmm::GaussianDistribution::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::GaussianDistribution::onAttributeChange); + allocate(); +} + +xmm::GaussianDistribution::GaussianDistribution(GaussianDistribution const& src) + : dimension(src.dimension), + dimension_input(src.dimension_input), + mean(src.mean), + covariance_mode(src.covariance_mode), + covariance(src.covariance), + bimodal_(src.bimodal_), + covariance_determinant_(src.covariance_determinant_), + inverse_covariance_(src.inverse_covariance_) { + dimension.onAttributeChange(this, + &xmm::GaussianDistribution::onAttributeChange); + dimension_input.onAttributeChange( + this, &xmm::GaussianDistribution::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::GaussianDistribution::onAttributeChange); + covariance_determinant_input_ = src.covariance_determinant_input_; + inverse_covariance_input_ = src.inverse_covariance_input_; + output_covariance = src.output_covariance; +} + +xmm::GaussianDistribution::GaussianDistribution(Json::Value const& root) + : covariance_determinant_(0.), covariance_determinant_input_(0.) { + bimodal_ = root.get("bimodal", false).asBool(); + dimension.set(root.get("dimension", bimodal_ ? 2 : 1).asInt()); + dimension_input.set(root.get("dimension_input", bimodal_ ? 1 : 0).asInt()); + covariance_mode.set( + static_cast<CovarianceMode>(root["covariance_mode"].asInt())); + + allocate(); + + json2vector(root["mean"], mean, dimension.get()); + json2vector(root["covariance"], covariance, + dimension.get() * dimension.get()); + + // updateInverseCovariance(); + // read from json instead of calling updateInverseCovariance() : + json2vector(root["inverse_covariance"], inverse_covariance_, + dimension.get() * dimension.get()); + covariance_determinant_ = root.get("covariance_determinant", 0.).asDouble(); + json2vector(root["inverse_covariance_input"], inverse_covariance_input_, + dimension_input.get() * dimension_input.get()); + covariance_determinant_input_ = + root.get("covariance_determinant_input", 0.).asDouble(); + + dimension.onAttributeChange(this, + &xmm::GaussianDistribution::onAttributeChange); + dimension_input.onAttributeChange( + this, &xmm::GaussianDistribution::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::GaussianDistribution::onAttributeChange); +} + +xmm::GaussianDistribution& xmm::GaussianDistribution::operator=( + GaussianDistribution const& src) { + if (this != &src) { + bimodal_ = src.bimodal_; + dimension = src.dimension; + dimension_input = src.dimension_input; + covariance_mode = src.covariance_mode; + + mean = src.mean; + covariance = src.covariance; + inverse_covariance_ = src.inverse_covariance_; + covariance_determinant_ = src.covariance_determinant_; + covariance_determinant_input_ = src.covariance_determinant_input_; + inverse_covariance_input_ = src.inverse_covariance_input_; + output_covariance = src.output_covariance; + } + return *this; +}; + +void xmm::GaussianDistribution::onAttributeChange(AttributeBase* attr_pointer) { + if (attr_pointer == &dimension) { + dimension_input.setLimitMax(dimension.get() - 1); + } + if (attr_pointer == &dimension || attr_pointer == &dimension_input) { + allocate(); + } + if (attr_pointer == &covariance_mode) { + if (covariance_mode.get() == CovarianceMode::Diagonal) { + std::vector<double> new_covariance(dimension.get()); + for (unsigned int d = 0; d < dimension.get(); ++d) { + new_covariance[d] = covariance[d * dimension.get() + d]; + } + covariance = new_covariance; + inverse_covariance_.resize(dimension.get()); + if (bimodal_) + inverse_covariance_input_.resize(dimension_input.get()); + } else if (covariance_mode.get() == CovarianceMode::Full) { + std::vector<double> new_covariance( + dimension.get() * dimension.get(), 0.0); + for (unsigned int d = 0; d < dimension.get(); ++d) { + new_covariance[d * dimension.get() + d] = covariance[d]; + } + covariance = new_covariance; + inverse_covariance_.resize(dimension.get() * dimension.get()); + if (bimodal_) + inverse_covariance_input_.resize(dimension_input.get() * + dimension_input.get()); + } + updateInverseCovariance(); + if (bimodal_) { + updateOutputCovariance(); + } + } + attr_pointer->changed = false; +} + +#pragma mark Likelihood & Regression +double xmm::GaussianDistribution::likelihood(const float* observation) const { + if (covariance_determinant_ == 0.0) + throw std::runtime_error("Covariance Matrix is not invertible"); + + double euclidianDistance(0.0); + if (covariance_mode.get() == CovarianceMode::Full) { + for (int l = 0; l < dimension.get(); l++) { + double tmp(0.0); + for (int k = 0; k < dimension.get(); k++) { + tmp += inverse_covariance_[l * dimension.get() + k] * + (observation[k] - mean[k]); + } + euclidianDistance += (observation[l] - mean[l]) * tmp; + } + } else { + for (int l = 0; l < dimension.get(); l++) { + euclidianDistance += inverse_covariance_[l] * + (observation[l] - mean[l]) * + (observation[l] - mean[l]); + } + } + + double p = + exp(-0.5 * euclidianDistance) / + sqrt(covariance_determinant_ * pow(2 * M_PI, double(dimension.get()))); + + if (p < 1e-180 || std::isnan(p) || std::isinf(fabs(p))) p = 1e-180; + + return p; +} + +double xmm::GaussianDistribution::likelihood_input( + const float* observation_input) const { + if (!bimodal_) + throw std::runtime_error( + "'likelihood_input' can't be used when 'bimodal_' is off."); + + if (covariance_determinant_input_ == 0.0) + throw std::runtime_error( + "Covariance Matrix of input modality is not invertible"); + + double euclidianDistance(0.0); + if (covariance_mode.get() == CovarianceMode::Full) { + for (int l = 0; l < dimension_input.get(); l++) { + double tmp(0.0); + for (int k = 0; k < dimension_input.get(); k++) { + tmp += + inverse_covariance_input_[l * dimension_input.get() + k] * + (observation_input[k] - mean[k]); + } + euclidianDistance += (observation_input[l] - mean[l]) * tmp; + } + } else { + for (int l = 0; l < dimension_input.get(); l++) { + euclidianDistance += inverse_covariance_[l] * + (observation_input[l] - mean[l]) * + (observation_input[l] - mean[l]); + } + } + + double p = exp(-0.5 * euclidianDistance) / + sqrt(covariance_determinant_input_ * + pow(2 * M_PI, double(dimension_input.get()))); + + if (p < 1e-180 || std::isnan(p) || std::isinf(fabs(p))) p = 1e-180; + + return p; +} + +double xmm::GaussianDistribution::likelihood_bimodal( + const float* observation_input, const float* observation_output) const { + if (!bimodal_) + throw std::runtime_error( + "'likelihood_bimodal' can't be used when 'bimodal_' is off."); + + if (covariance_determinant_ == 0.0) + throw std::runtime_error("Covariance Matrix is not invertible"); + + unsigned int dimension_output = dimension.get() - dimension_input.get(); + double euclidianDistance(0.0); + if (covariance_mode.get() == CovarianceMode::Full) { + for (int l = 0; l < dimension.get(); l++) { + double tmp(0.0); + for (int k = 0; k < dimension_input.get(); k++) { + tmp += inverse_covariance_[l * dimension.get() + k] * + (observation_input[k] - mean[k]); + } + for (int k = 0; k < dimension_output; k++) { + tmp += + inverse_covariance_[l * dimension.get() + + dimension_input.get() + k] * + (observation_output[k] - mean[dimension_input.get() + k]); + } + if (l < dimension_input.get()) + euclidianDistance += (observation_input[l] - mean[l]) * tmp; + else + euclidianDistance += + (observation_output[l - dimension_input.get()] - mean[l]) * + tmp; + } + } else { + for (int l = 0; l < dimension_input.get(); l++) { + euclidianDistance += inverse_covariance_[l] * + (observation_input[l] - mean[l]) * + (observation_input[l] - mean[l]); + } + for (unsigned int l = dimension_input.get(); l < dimension.get(); l++) { + euclidianDistance += + inverse_covariance_[l] * + (observation_output[l - dimension_input.get()] - mean[l]) * + (observation_output[l - dimension_input.get()] - mean[l]); + } + } + + double p = + exp(-0.5 * euclidianDistance) / + sqrt(covariance_determinant_ * pow(2 * M_PI, (double)dimension.get())); + + if (p < 1e-180 || std::isnan(p) || std::isinf(fabs(p))) p = 1e-180; + + return p; +} + +void xmm::GaussianDistribution::regression( + std::vector<float> const& observation_input, + std::vector<float>& predicted_output) const { + if (!bimodal_) + throw std::runtime_error( + "'regression' can't be used when 'bimodal_' is off."); + + unsigned int dimension_output = dimension.get() - dimension_input.get(); + predicted_output.resize(dimension_output); + + if (covariance_mode.get() == CovarianceMode::Full) { + for (int d = 0; d < dimension_output; d++) { + predicted_output[d] = mean[dimension_input.get() + d]; + for (int e = 0; e < dimension_input.get(); e++) { + float tmp = 0.; + for (int f = 0; f < dimension_input.get(); f++) { + tmp += inverse_covariance_input_[e * dimension_input.get() + + f] * + (observation_input[f] - mean[f]); + } + predicted_output[d] += + covariance[(d + dimension_input.get()) * dimension.get() + + e] * + tmp; + } + } + } else { + for (int d = 0; d < dimension_output; d++) { + predicted_output[d] = mean[dimension_input.get() + d]; + } + } +} + +#pragma mark JSON I/O +Json::Value xmm::GaussianDistribution::toJson() const { + Json::Value root; + root["bimodal"] = bimodal_; + root["dimension"] = static_cast<int>(dimension.get()); + root["dimension_input"] = static_cast<int>(dimension_input.get()); + root["covariance_mode"] = static_cast<int>(covariance_mode.get()); + root["mean"] = vector2json(mean); + root["covariance"] = vector2json(covariance); + + root["inverse_covariance"] = vector2json(inverse_covariance_); + root["covariance_determinant"] = covariance_determinant_; + root["inverse_covariance_input"] = vector2json(inverse_covariance_input_); + root["covariance_determinant_input"] = covariance_determinant_input_; + + return root; +} + +void xmm::GaussianDistribution::fromJson(Json::Value const& root) { + try { + GaussianDistribution tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +#pragma mark Utilities +void xmm::GaussianDistribution::allocate() { + mean.resize(dimension.get()); + if (covariance_mode.get() == CovarianceMode::Full) { + covariance.resize(dimension.get() * dimension.get()); + inverse_covariance_.resize(dimension.get() * dimension.get()); + if (bimodal_) + inverse_covariance_input_.resize(dimension_input.get() * + dimension_input.get()); + } else { + covariance.resize(dimension.get()); + inverse_covariance_.resize(dimension.get()); + if (bimodal_) inverse_covariance_input_.resize(dimension_input.get()); + } +} + +void xmm::GaussianDistribution::regularize(std::vector<double> regularization) { + if (covariance_mode.get() == CovarianceMode::Full) { + for (int d = 0; d < dimension.get(); ++d) { + covariance[d * dimension.get() + d] += regularization[d]; + } + } else { + for (int d = 0; d < dimension.get(); ++d) { + covariance[d] += regularization[d]; + } + } +} + +void xmm::GaussianDistribution::updateInverseCovariance() { + if (covariance_mode.get() == CovarianceMode::Full) { + Matrix<double> cov_matrix(dimension.get(), dimension.get(), false); + + Matrix<double>* inverseMat; + double det; + + cov_matrix.data = covariance.begin(); + inverseMat = cov_matrix.pinv(&det); + covariance_determinant_ = det; + copy(inverseMat->data, + inverseMat->data + dimension.get() * dimension.get(), + inverse_covariance_.begin()); + delete inverseMat; + inverseMat = NULL; + + // If regression active: create inverse covariance matrix for input + // modality. + if (bimodal_) { + Matrix<double> cov_matrix_input(dimension_input.get(), + dimension_input.get(), true); + for (int d1 = 0; d1 < dimension_input.get(); d1++) { + for (int d2 = 0; d2 < dimension_input.get(); d2++) { + cov_matrix_input._data[d1 * dimension_input.get() + d2] = + covariance[d1 * dimension.get() + d2]; + } + } + inverseMat = cov_matrix_input.pinv(&det); + covariance_determinant_input_ = det; + copy(inverseMat->data, + inverseMat->data + + dimension_input.get() * dimension_input.get(), + inverse_covariance_input_.begin()); + delete inverseMat; + inverseMat = NULL; + } + } else // DIAGONAL COVARIANCE + { + covariance_determinant_ = 1.; + covariance_determinant_input_ = 1.; + for (unsigned int d = 0; d < dimension.get(); ++d) { + if (covariance[d] <= 0.0) + throw std::runtime_error("Non-invertible matrix"); + inverse_covariance_[d] = 1. / covariance[d]; + covariance_determinant_ *= covariance[d]; + if (bimodal_ && d < dimension_input.get()) { + inverse_covariance_input_[d] = 1. / covariance[d]; + covariance_determinant_input_ *= covariance[d]; + } + } + } + if (bimodal_) { + this->updateOutputCovariance(); + } +} + +void xmm::GaussianDistribution::updateOutputCovariance() { + if (!bimodal_) + throw std::runtime_error( + "'updateOutputVariances' can't be used when 'bimodal_' is off."); + + unsigned int dimension_output = dimension.get() - dimension_input.get(); + + // CASE: DIAGONAL COVARIANCE + if (covariance_mode.get() == CovarianceMode::Diagonal) { + output_covariance.resize(dimension_output); + copy(covariance.begin() + dimension_input.get(), + covariance.begin() + dimension.get(), output_covariance.begin()); + return; + } + + // CASE: FULL COVARIANCE + Matrix<double>* inverseMat; + double det; + + Matrix<double> cov_matrix_input(dimension_input.get(), + dimension_input.get(), true); + for (int d1 = 0; d1 < dimension_input.get(); d1++) { + for (int d2 = 0; d2 < dimension_input.get(); d2++) { + cov_matrix_input._data[d1 * dimension_input.get() + d2] = + covariance[d1 * dimension.get() + d2]; + } + } + inverseMat = cov_matrix_input.pinv(&det); + Matrix<double> covariance_gs(dimension_input.get(), dimension_output, true); + for (int d1 = 0; d1 < dimension_input.get(); d1++) { + for (int d2 = 0; d2 < dimension_output; d2++) { + covariance_gs._data[d1 * dimension_output + d2] = + covariance[d1 * dimension.get() + dimension_input.get() + d2]; + } + } + Matrix<double> covariance_sg(dimension_output, dimension_input.get(), true); + for (int d1 = 0; d1 < dimension_output; d1++) { + for (int d2 = 0; d2 < dimension_input.get(); d2++) { + covariance_sg._data[d1 * dimension_input.get() + d2] = + covariance[(dimension_input.get() + d1) * dimension.get() + d2]; + } + } + Matrix<double>* tmptmptmp = inverseMat->product(&covariance_gs); + Matrix<double>* covariance_mod = covariance_sg.product(tmptmptmp); + output_covariance.resize(dimension_output * dimension_output); + for (int d1 = 0; d1 < dimension_output; d1++) { + for (int d2 = 0; d2 < dimension_output; d2++) { + output_covariance[d1 * dimension_output + d2] = + covariance[(dimension_input.get() + d1) * dimension.get() + + dimension_input.get() + d2] - + covariance_mod->data[d1 * dimension_output + d2]; + } + } + delete inverseMat; + delete covariance_mod; + delete tmptmptmp; + inverseMat = NULL; + covariance_mod = NULL; + tmptmptmp = NULL; +} + +xmm::Ellipse xmm::GaussianDistribution::toEllipse(unsigned int dimension1, + unsigned int dimension2) { + if (dimension1 >= dimension.get() || dimension2 >= dimension.get()) + throw std::out_of_range("dimensions out of range"); + + Ellipse gaussian_ellipse; + gaussian_ellipse.x = mean[dimension1]; + gaussian_ellipse.y = mean[dimension2]; + + // Represent 2D covariance with square matrix + // |a b| + // |b c| + double a, b, c; + if (covariance_mode.get() == CovarianceMode::Full) { + a = covariance[dimension1 * dimension.get() + dimension1]; + b = covariance[dimension1 * dimension.get() + dimension2]; + c = covariance[dimension2 * dimension.get() + dimension2]; + } else { + a = covariance[dimension1]; + b = 0.0; + c = covariance[dimension2]; + } + + // Compute Eigen Values to get width, height and angle + double trace = a + c; + double determinant = a * c - b * b; + double eigenVal1 = 0.5 * (trace + sqrt(trace * trace - 4 * determinant)); + double eigenVal2 = 0.5 * (trace - sqrt(trace * trace - 4 * determinant)); + gaussian_ellipse.width = sqrt(5.991 * eigenVal1); + gaussian_ellipse.height = sqrt(5.991 * eigenVal2); + gaussian_ellipse.angle = atan(b / (eigenVal1 - c)); + if (isnan(gaussian_ellipse.angle)) { + gaussian_ellipse.angle = M_PI_2; + } + + return gaussian_ellipse; +} + +void xmm::GaussianDistribution::fromEllipse(Ellipse const& gaussian_ellipse, + unsigned int dimension1, + unsigned int dimension2) { + if (dimension1 >= dimension.get() || dimension2 >= dimension.get()) + throw std::out_of_range("dimensions out of range"); + + mean[dimension1] = gaussian_ellipse.x; + mean[dimension2] = gaussian_ellipse.y; + + double eigenVal1 = gaussian_ellipse.width * gaussian_ellipse.width / 5.991; + double eigenVal2 = + gaussian_ellipse.height * gaussian_ellipse.height / 5.991; + double tantheta = std::tan(gaussian_ellipse.angle); + double a, b, c; + b = (eigenVal1 - eigenVal2) * tantheta / (tantheta * tantheta + 1.); + c = eigenVal1 - b / tantheta; + a = eigenVal2 + b / tantheta; + + if (covariance_mode.get() == CovarianceMode::Full) { + covariance[dimension1 * dimension.get() + dimension1] = a; + covariance[dimension1 * dimension.get() + dimension2] = b; + covariance[dimension2 * dimension.get() + dimension1] = b; + covariance[dimension2 * dimension.get() + dimension2] = c; + } else { + covariance[dimension1] = a; + covariance[dimension2] = c; + } + updateInverseCovariance(); +} + +// void xmm::GaussianDistribution::makeBimodal(unsigned int dimension_input_) +//{ +// if (bimodal_) +// throw std::runtime_error("The model is already bimodal"); +// if (dimension_input_ >= dimension.get()) +// throw std::out_of_range("Request input dimension exceeds the current +// dimension"); +// this->bimodal_ = true; +// dimension_input.setLimitMax(dimension.get() - 1); +// dimension_input.set(dimension_input_, true); +// if (covariance_mode.get() == CovarianceMode::Full) { +// this->inverse_covariance_input_.resize(dimension_input_*dimension_input_); +// } else { +// this->inverse_covariance_input_.resize(dimension_input_); +// } +// this->updateInverseCovariance(); +// this->updateOutputVariance(); +//} +// +// void xmm::GaussianDistribution::makeUnimodal() +//{ +// if (!bimodal_) +// throw std::runtime_error("The model is already unimodal"); +// this->bimodal_ = false; +// this->dimension_input.set(0, true); +// this->inverse_covariance_input_.clear(); +//} +// +// xmm::GaussianDistribution +// xmm::GaussianDistribution::extractSubmodel(std::vector<unsigned int>& +// columns) +// const +//{ +// if (columns.size() > dimension.get()) +// throw std::out_of_range("requested number of columns exceeds the +// dimension of the current model"); +// for (unsigned int column=0; column<columns.size(); ++column) { +// if (columns[column] >= dimension.get()) +// throw std::out_of_range("Some column indices exceeds the dimension +// of the current model"); +// } +// size_t new_dim =columns.size(); +// GaussianDistribution target_distribution(NONE, +// static_cast<unsigned int>(new_dim), 0, relative_regularization, +// absolute_regularization); +// target_distribution.allocate(); +// for (unsigned int new_index1=0; new_index1<new_dim; ++new_index1) { +// unsigned int col_index1 = columns[new_index1]; +// target_distribution.mean[new_index1] = mean[col_index1]; +// target_distribution.scale[new_index1] = scale[col_index1]; +// if (covariance_mode.get() == CovarianceMode::Full) { +// for (unsigned int new_index2=0; new_index2<new_dim; ++new_index2) +// { +// unsigned int col_index2 = columns[new_index2]; +// target_distribution.covariance[new_index1*new_dim+new_index2] +// = covariance[col_index1*dimension.get()+col_index2]; +// } +// } else { +// target_distribution.covariance[new_index1] = +// covariance[col_index1]; +// } +// } +// try { +// target_distribution.updateInverseCovariance(); +// } catch (std::exception const& e) { +// } +// return target_distribution; +//} +// +// xmm::GaussianDistribution xmm::GaussianDistribution::extractSubmodel_input() +// const +//{ +// if (!bimodal_) +// throw std::runtime_error("The distribution needs to be bimodal"); +// std::vector<unsigned int> columns_input(dimension_input.get()); +// for (unsigned int i=0; i<dimension_input.get(); ++i) { +// columns_input[i] = i; +// } +// return extractSubmodel(columns_input); +//} +// +// xmm::GaussianDistribution xmm::GaussianDistribution::extractSubmodel_output() +// const +//{ +// if (!bimodal_) +// throw std::runtime_error("The distribution needs to be bimodal"); +// std::vector<unsigned int> columns_output(dimension.get() - +// dimension_input.get()); +// for (unsigned int i=dimension_input.get(); i<dimension.get(); ++i) { +// columns_output[i-dimension_input.get()] = i; +// } +// return extractSubmodel(columns_output); +//} +// +// xmm::GaussianDistribution xmm::GaussianDistribution::extract_inverse_model() +// const +//{ +// if (!bimodal_) +// throw std::runtime_error("The distribution needs to be bimodal"); +// std::vector<unsigned int> columns(dimension.get()); +// for (unsigned int i=0; i<dimension.get()-dimension_input.get(); ++i) { +// columns[i] = i + dimension_input.get(); +// } +// for (unsigned int i=dimension.get()-dimension_input.get(), j=0; +// i<dimension.get(); ++i, ++j) { +// columns[i] = j; +// } +// GaussianDistribution target_distribution = extractSubmodel(columns); +// target_distribution.makeBimodal(dimension.get() - dimension_input.get()); +// return target_distribution; +//} + +xmm::Ellipse xmm::covariance2ellipse(double c_xx, double c_xy, double c_yy) { + Ellipse gaussian_ellipse; + gaussian_ellipse.x = 0.; + gaussian_ellipse.y = 0.; + + // Compute Eigen Values to get width, height and angle + double trace = c_xx + c_yy; + double determinant = c_xx * c_yy - c_xy * c_xy; + double eigenVal1 = 0.5 * (trace + sqrt(trace * trace - 4 * determinant)); + double eigenVal2 = 0.5 * (trace - sqrt(trace * trace - 4 * determinant)); + gaussian_ellipse.width = sqrt(5.991 * eigenVal1); + gaussian_ellipse.height = sqrt(5.991 * eigenVal2); + gaussian_ellipse.angle = atan(c_xy / (eigenVal1 - c_yy)); + if (isnan(gaussian_ellipse.angle)) { + gaussian_ellipse.angle = M_PI_2; + } + + return gaussian_ellipse; +} + +template <> +void xmm::checkLimits<xmm::GaussianDistribution::CovarianceMode>( + xmm::GaussianDistribution::CovarianceMode const& value, + xmm::GaussianDistribution::CovarianceMode const& limit_min, + xmm::GaussianDistribution::CovarianceMode const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error( + "Attribute value out of range. Range: [" + + std::to_string(static_cast<int>(limit_min)) + " ; " + + std::to_string(static_cast<int>(limit_max)) + "]"); +} + +template <> +xmm::GaussianDistribution::CovarianceMode +xmm::Attribute<xmm::GaussianDistribution::CovarianceMode>::defaultLimitMax() { + return xmm::GaussianDistribution::CovarianceMode::Diagonal; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/distributions/xmmGaussianDistribution.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/distributions/xmmGaussianDistribution.hpp new file mode 100644 index 0000000000000000000000000000000000000000..646e15684deccc6b93998ffbd9141ba4b14a9053 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/distributions/xmmGaussianDistribution.hpp @@ -0,0 +1,376 @@ +/* + * xmmGaussianDistribution.hpp + * + * Multivariate Gaussian Distribution + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmGaussianDistribution_h +#define xmmGaussianDistribution_h + +#include "../common/xmmAttribute.hpp" +#include "../common/xmmJson.hpp" + +namespace xmm { +/** + @defgroup Distributions [Core] Distributions + */ + +/** + @ingroup Distributions + @brief Structure for storing Ellipse parameters + */ +struct Ellipse { + /** + @brief x center position + */ + float x; + + /** + @brief y center position + */ + float y; + + /** + @brief width: minor axis length + */ + float width; + + /** + @brief height: major axis length + */ + float height; + + /** + @brief angle (radians) + */ + float angle; +}; + +/** + @ingroup Distributions + @brief Multivariate Gaussian Distribution + @details Full covariance, optionally multimodal with support for regression + */ +class GaussianDistribution : public Writable { + public: + /** + @brief Covariance Mode + */ + enum class CovarianceMode { + /** + @brief Full covariance + */ + Full = 0, + + /** + @brief Diagonal covariance (diagonal matrix) + */ + Diagonal = 1 + }; + + /** + @brief Default Constructor + @param bimodal specify if the distribution is bimodal for use in regression + @param dimension dimension of the distribution + @param dimension_input dimension of the input modality in bimodal mode. + @param covariance_mode covariance mode (full vs diagonal) + */ + GaussianDistribution(bool bimodal = false, unsigned int dimension = 1, + unsigned int dimension_input = 0, + CovarianceMode covariance_mode = CovarianceMode::Full); + + /** + @brief Copy constructor + @param src source distribution + */ + GaussianDistribution(GaussianDistribution const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit GaussianDistribution(Json::Value const& root); + + /** + @brief Assignment + @param src source distribution + */ + GaussianDistribution& operator=(GaussianDistribution const& src); + + /** @name Likelihood & Regression */ + ///@{ + + /** + @brief Get Likelihood of a data vector + @param observation data observation (must be of size @a dimension) + @return likelihood + @throws runtime_error if the Covariance Matrix is not invertible + */ + double likelihood(const float* observation) const; + + /** + @brief Get Likelihood of a data vector for input modality + @param observation_input observation (must be of size @a dimension_input) + @return likelihood + @throws runtime_error if the Covariance Matrix of the input modality is not + invertible + @throws runtime_error if the model is not bimodal + */ + double likelihood_input(const float* observation_input) const; + + /** + @brief Get Likelihood of a data vector for bimodal mode + @param observation_input observation of the input modality + @param observation_output observation of the output modality + @throws runtime_error if the Covariance Matrix is not invertible + @throws runtime_error if the model is not bimodal + @return likelihood + */ + double likelihood_bimodal(const float* observation_input, + const float* observation_output) const; + + /** + @brief Linear Regression using the Gaussian Distribution (covariance-based) + @param observation_input input observation (must be of size: @a + dimension_input) + @param predicted_output predicted output vector (size: + dimension-dimension_input) + @throws runtime_error if the model is not bimodal + */ + void regression(std::vector<float> const& observation_input, + std::vector<float>& predicted_output) const; + + ///@} + + /** @name Utilities */ + ///@{ + + /** + @brief Add @a offset to the diagonal of the covariance matrix + @details Ensures convergence + generalization on few examples + */ + void regularize(std::vector<double> regularization); + + /** + @brief Compute inverse covariance matrix + @throws runtime_error if the covariance matrix is not invertible + */ + void updateInverseCovariance(); + + /** + @brief Compute the 68%?? Confidence Interval ellipse of the Gaussian + @details the ellipse is 2D, and is therefore projected over 2 axes + @param dimension1 index of the first axis + @param dimension2 index of the second axis + @throws out_of_range if the dimensions are out of bounds + @return ellipse parameters + */ + Ellipse toEllipse(unsigned int dimension1, unsigned int dimension2); + + /** + @brief Sets the parameters of the Gaussian distribution according to the + 68%?? Confidence Interval ellipse + @details the ellipse is 2D, and is therefore projected over 2 axes + @param gaussian_ellipse 68% Confidence Interval ellipse parameters (1x std) + @param dimension1 index of the first axis + @param dimension2 index of the second axis + @throws out_of_range if the dimensions are out of bounds + */ + void fromEllipse(Ellipse const& gaussian_ellipse, unsigned int dimension1, + unsigned int dimension2); + + ///@} + + /** @name JSON I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + void fromJson(Json::Value const& root); + + ///@} + + // /** @name Conversion & Extraction */ + // ///@{ + // + // /** + // @brief Convert to bimodal distribution in place + // @param dimension_input dimension of the input modality + // @throws runtime_error if the model is already bimodal + // @throws out_of_range if the requested input dimension is too + // large + // */ + // void makeBimodal(unsigned int dimension_input); + // + // /** + // @brief Convert to unimodal distribution in place + // @throws runtime_error if the model is already unimodal + // */ + // void makeUnimodal(); + // + // /** + // @brief extract a sub-distribution with the given columns + // @param columns columns indices in the target order + // @throws runtime_error if the model is training + // @throws out_of_range if the number or indices of the requested + // columns exceeds the current dimension + // @return a Gaussian Distribution from the current model + // considering only the target columns + // */ + // GaussianDistribution extractSubmodel(std::vector<unsigned int>& + // columns) const; + // + // /** + // @brief extract the sub-distribution of the input modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal Gaussian Distribution of the input modality + // from the current bimodal model + // */ + // GaussianDistribution extractSubmodel_input() const; + // + // /** + // @brief extract the sub-distribution of the output modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal Gaussian Distribution of the output modality + // from the current bimodal model + // */ + // GaussianDistribution extractSubmodel_output() const; + // + // /** + // @brief extract the model with reversed input and output + // modalities + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a bimodal Gaussian Distribution that swaps the input and + // output modalities + // */ + // GaussianDistribution extract_inverse_model() const; + // + // ///@} + + /** + @brief Total Dimension of the multivariate normal + */ + Attribute<unsigned int> dimension; + + /** + @brief Input Dimension of the multivariate normal + */ + Attribute<unsigned int> dimension_input; + + /** + @brief Mean of the Gaussian Distribution + */ + std::vector<double> mean; + + /** + @brief Covariance Mode + */ + Attribute<CovarianceMode> covariance_mode; + + /** + @brief Covariance Matrix of the Gaussian Distribution + */ + std::vector<double> covariance; + + /** + @brief Conditional Output Variance (updated when covariances matrices are + inverted) + */ + std::vector<double> output_covariance; + + protected: + /** + @brief Resize Mean and Covariance Vectors to appropriate dimension. + */ + void allocate(); + + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); + + /** + @brief Compute the conditional variance vector of the output modality + (conditioned over the input). + @throws runtime_error if the model is not bimodal + */ + void updateOutputCovariance(); + + /** + @brief Defines if regression parameters need to be computed + */ + bool bimodal_; + + /** + @brief Determinant of the covariance matrix + */ + double covariance_determinant_; + + /** + @brief Inverse covariance matrix + */ + std::vector<double> inverse_covariance_; + + /** + @brief Determinant of the covariance matrix of the input modality + */ + double covariance_determinant_input_; + + /** + @brief Inverse covariance matrix of the input modality + */ + std::vector<double> inverse_covariance_input_; +}; + +Ellipse covariance2ellipse(double c_xx, double c_xy, double c_yy); + +template <> +void checkLimits<GaussianDistribution::CovarianceMode>( + GaussianDistribution::CovarianceMode const& value, + GaussianDistribution::CovarianceMode const& limit_min, + GaussianDistribution::CovarianceMode const& limit_max); + +template <> +GaussianDistribution::CovarianceMode +Attribute<GaussianDistribution::CovarianceMode>::defaultLimitMax(); +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModel.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModel.hpp new file mode 100644 index 0000000000000000000000000000000000000000..522660b7bee12264ce8fbe28da930181c17d0c3f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModel.hpp @@ -0,0 +1,633 @@ +/* + * xmmModel.hpp + * + * Probabilistic machine learning model for multiclass recognition and + * regression + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmModel_h +#define xmmModel_h + +#include "xmmModelConfiguration.hpp" +#include "xmmModelResults.hpp" +#include "xmmModelSingleClass.hpp" +#include <atomic> +#include <thread> + +namespace xmm { +/** + @ingroup Model + @brief Probabilistic machine learning model for multiclass recognition and + regression + @tparam SingleClassModel Type of the associated Single-class Model + @tparam ModelType Model Type Name + */ +template <typename SingleClassModel, typename ModelType> +class Model : public Writable { + public: + /** + @brief Constructor + @param bimodal use true for a use with Regression / Generation. + */ + Model(bool bimodal = false) + : shared_parameters(std::make_shared<SharedParameters>()), + cancel_required_(false), + is_training_(false), + is_joining_(false), + models_still_training_(0) { + shared_parameters->bimodal.set(bimodal); + if (shared_parameters->bimodal.get()) { + shared_parameters->dimension.set(2, true); + shared_parameters->dimension_input.set(1, true); + } else { + shared_parameters->dimension.set(1, true); + shared_parameters->dimension_input.set(0, true); + } + } + + /** + @brief Copy Constructor + @param src Source Model + */ + Model(Model<SingleClassModel, ModelType> const& src) + : shared_parameters( + std::make_shared<SharedParameters>(*src.shared_parameters)), + configuration(src.configuration), + training_events(src.training_events), + cancel_required_(false), + is_training_(false), + is_joining_(false), + models_still_training_(0) { + if (src.is_training_) + throw std::runtime_error( + "Cannot copy: source model is still training"); + models = src.models; + for (auto& model : models) { + model.second.training_events.removeListeners(); + model.second.training_events.addListener( + this, + &xmm::Model<SingleClassModel, ModelType>::onTrainingEvent); + } + } + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit Model(Json::Value const& root) + : shared_parameters(std::make_shared<SharedParameters>()), + cancel_required_(false), + is_training_(false), + is_joining_(false), + models_still_training_(0) { + shared_parameters->fromJson(root["shared_parameters"]); + configuration.fromJson(root["configuration"]); + models.clear(); + for (auto p : root["models"]) { + std::string l = p["label"].asString(); + models.insert(std::pair<std::string, SingleClassModel>( + l, SingleClassModel(shared_parameters, p))); + models[l].training_events.removeListeners(); + models[l].training_events.addListener( + this, + &xmm::Model<SingleClassModel, ModelType>::onTrainingEvent); + } + } + + /** + @brief Assignment + @param src Source Model + */ + Model<SingleClassModel, ModelType>& operator=( + Model<SingleClassModel, ModelType> const& src) { + if (this != &src) { + if (is_training_) + throw std::runtime_error( + "Cannot copy: target model is still training"); + if (src.is_training_) + throw std::runtime_error( + "Cannot copy: source model is still training"); + shared_parameters = + std::make_shared<SharedParameters>(*src.shared_parameters); + configuration = src.configuration; + training_events = src.training_events; + is_joining_ = false; + is_training_ = false; + cancel_required_ = false; + models_still_training_ = 0; + + models.clear(); + models = src.models; + for (auto& model : this->models) { + model.second.training_events.removeListeners(); + model.second.training_events.addListener( + this, + &xmm::Model<SingleClassModel, ModelType>::onTrainingEvent); + } + } + return *this; + } + + /** + @brief Destructor + */ + virtual ~Model() { + cancelTraining(); + clear(); + } + + /** @name Class Manipulation */ + ///@{ + + /** + @brief Get the number of classes in the model + @return the number of classes in the model + */ + unsigned int size() const { + return static_cast<unsigned int>(models.size()); + } + + /** + @brief Checks if a class exists + @param label class label + @return true if the class labeled 'label' exists + */ + bool hasClass(std::string const& label) const { + checkTraining(); + return (models.count(label) > 0); + } + + /** + @brief Checks if a class exists + @param label class label + @return true if the class labeled 'label' exists + */ + int getIndex(std::string const& label) const { + checkTraining(); + int i(-1); + for (auto& m : models) { + i++; + if (m.first == label) { + return i; + } + } + return -1; + } + + /** + @brief Remove a specific class by label + @param label label of the class to remove + */ + virtual void removeClass(std::string const& label) { + while (is_joining_) { + } + cancelTraining(label); + auto it = models.find(label); + if (it == models.end()) + throw std::out_of_range("Class " + label + " does not exist"); + models.erase(it); + reset(); + } + + /** + @brief Remove all classes + */ + virtual void clear() { + if (is_training_) cancelTraining(); + models.clear(); + reset(); + } + + ///@} + + /** @name Training */ + ///@{ + + /** + @brief Checks if the model is trained (training finished and not empty) + */ + bool trained() const { return (!is_training_ && size() > 0); } + + /** + @brief Checks if the model is still training + */ + bool training() const { return is_training_; } + + /** + @brief Train all classes from the training set passed in argument + @param trainingSet Training Set + */ + virtual void train(TrainingSet* trainingSet) { + if (!trainingSet) return; + cancelTraining(); + clear(); + + is_training_ = true; + + // Fetch training set parameters + shared_parameters->dimension.set(trainingSet->dimension.get()); + if (shared_parameters->bimodal.get()) { + shared_parameters->dimension_input.set( + trainingSet->dimension_input.get()); + } + shared_parameters->column_names.set(trainingSet->column_names.get()); + + // Update models + bool contLoop(true); + while (contLoop) { + contLoop = false; + for (auto it = models.begin(); it != models.end(); ++it) { + if (trainingSet->labels().count(it->first) == 0) { + models.erase(it->first); + contLoop = true; + break; + } + } + } + for (typename std::set<std::string>::iterator it = + trainingSet->labels().begin(); + it != trainingSet->labels().end(); ++it) { + addModelForClass(*it); + } + + // Start class training + for (auto it = this->models.begin(); it != this->models.end(); ++it) { + it->second.is_training_ = true; + it->second.cancel_training_ = false; + models_still_training_++; + if ((configuration.multithreading == + MultithreadingMode::Parallel) || + (configuration.multithreading == + MultithreadingMode::Background)) { + training_threads_[it->first] = + std::thread(&SingleClassModel::train, &it->second, + trainingSet->getPhrasesOfClass(it->first)); + } else { + it->second.train(trainingSet->getPhrasesOfClass(it->first)); + } + } + if (configuration.multithreading == MultithreadingMode::Parallel) { + joinTraining(); + } + if (configuration.multithreading == MultithreadingMode::Sequential) { + is_training_ = false; + } + } + + /** + @brief Train a specific class from the training set passed in argument + @param trainingSet Training Set + @param label label of the class to train + @throw out_of_range if the label does not exist + @throw runtime_error if the dimensions of the training set don't match the + dimensions + of the current model + */ + virtual void train(TrainingSet* trainingSet, std::string const& label) { + if (!trainingSet) return; + if (trainingSet->labels().count(label) == 0) + throw std::out_of_range("Class " + label + " does not exist"); + + // Cancel Training of the class + cancelTraining(label); + + // Check Consistency of the new Training Set + if (size() > 0) { + if ((shared_parameters->dimension.get() != + trainingSet->dimension.get()) || + (shared_parameters->bimodal.get() && + (shared_parameters->dimension_input.get() != + trainingSet->dimension_input.get()))) + throw std::runtime_error( + "Dimensions of the new Training Set do not match existing " + "models"); + } + + is_training_ = true; + + // Fetch training set parameters + shared_parameters->dimension.set(trainingSet->dimension.get()); + if (shared_parameters->bimodal.get()) { + shared_parameters->dimension_input.set( + trainingSet->dimension_input.get()); + } + shared_parameters->column_names.set(trainingSet->column_names.get()); + + addModelForClass(label); + + // Start class training + models[label].is_training_ = true; + models[label].cancel_training_ = false; + models_still_training_++; + if (configuration.multithreading == MultithreadingMode::Sequential) { + models[label].train(trainingSet->getPhrasesOfClass(label)); + } else { + training_threads_[label] = + std::thread(&SingleClassModel::train, &(this->models[label]), + trainingSet->getPhrasesOfClass(label)); + } + if (configuration.multithreading == MultithreadingMode::Parallel) { + joinTraining(); + } + if (configuration.multithreading == MultithreadingMode::Sequential) { + is_training_ = false; + } + } + + /** + @brief Cancels the training of all models + */ + void cancelTraining() { + if (is_training_) { + for (auto& it : this->models) { + cancel_required_ = true; + it.second.cancelTraining(); + while (it.second.isTraining()) { + } + } + joinTraining(); + } + cancel_required_ = false; + } + + /** + @brief Cancels the training of a given class + @param label label of the class to cancel + */ + void cancelTraining(std::string const& label) { + if (is_training_ && (this->models.count(label) > 0)) { + cancel_required_ = true; + models[label].cancelTraining(); + while (models[label].isTraining()) { + } + if (models_still_training_ == 0) { + joinTraining(); + } + } + cancel_required_ = false; + } + + ///@} + + /** @name Performance */ + ///@{ + + /** + @brief Resets the fitering process (recognition or regression) + */ + virtual void reset() { + checkTraining(); + // checkConfigurationChanges(); + for (auto it = this->models.begin(); it != this->models.end(); ++it) { + it->second.reset(); + } + } + + /** + @brief filters a incoming observation (performs recognition or regression) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + */ + virtual void filter(std::vector<float> const& observation) { + checkTraining(); + // checkConfigurationChanges(); + } + + ///@} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const { + Json::Value root; + root["shared_parameters"] = shared_parameters->toJson(); + root["configuration"] = configuration.toJson(); + root["models"].resize(static_cast<Json::ArrayIndex>(size())); + Json::ArrayIndex modelIndex(0); + for (auto& it : models) { + root["models"][modelIndex++] = it.second.toJson(); + } + return root; + } + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + void fromJson(Json::Value const& root) { + try { + EventGenerator<TrainingEvent> _tmp_training_events(training_events); + Model<SingleClassModel, ModelType> tmp(root); + *this = tmp; + training_events = _tmp_training_events; + } catch (JsonException& e) { + throw e; + } + } + + ///@} + + /** + @brief Set of Parameters shared among classes + */ + std::shared_ptr<SharedParameters> shared_parameters; + + /** + @brief Configuration (default and class-specific parameters) + */ + Configuration<ModelType> configuration; + + /** + @brief Generator for training process events + */ + EventGenerator<TrainingEvent> training_events; + + /** + @brief models stored in a map. Each Model is associated with a label + */ + std::map<std::string, SingleClassModel> models; + + protected: + /** + @brief Finishes the background training process by joining threads and + deleting the models which training failed + */ + virtual void joinTraining() { + if (!is_training_) return; + bool expectedState(false); + if (is_joining_.compare_exchange_weak(expectedState, true)) { + while (!training_threads_.empty()) { + training_threads_.begin()->second.join(); + training_threads_.erase(training_threads_.begin()); + } + bool classesUntrained(true); + while (classesUntrained) { + classesUntrained = false; + for (auto it = this->models.begin(); it != this->models.end(); + it++) { + if (it->second.training_status.status == + TrainingEvent::Status::Cancel || + it->second.training_status.status == + TrainingEvent::Status::Error) { + models.erase(it); + classesUntrained = true; + break; + } + } + } + is_joining_ = false; + is_training_ = false; + reset(); + TrainingEvent event(this, "", TrainingEvent::Status::Alldone); + training_events.notifyListeners(event); + } else { + while (is_joining_) { + } + } + } + + /** + @brief Monitors the training of each Model of the group. + */ + void onTrainingEvent(TrainingEvent const& e) { + event_mutex_.lock(); + TrainingEvent event(e); + event.model = this; + training_events.notifyListeners(event); + if (e.status != TrainingEvent::Status::Run) { + models_still_training_--; + ((SingleClassModel*)e.model)->is_training_ = false; + if (configuration.multithreading == + MultithreadingMode::Background && + !is_joining_ && // avoid to call "joinTraining" if already + // called by the main thread + !cancel_required_ && // avoid to call "joinTraining" if cancel + // required by the main thread + models_still_training_ == 0) { + is_joining_ = false; + std::thread(&Model<SingleClassModel, ModelType>::joinTraining, + this) + .detach(); + } + } + event_mutex_.unlock(); + } + + /** + @brief Checks if the Model is still training + @throws runtime_error if the Model is training. + */ + inline void checkTraining() const { + if (is_training_) throw std::runtime_error("The Model is training"); + while (is_joining_) { + } + } + + /** + @brief Look for configuration changes and throws an exception if the model + is not up to date. + */ + inline void checkConfigurationChanges() const { + bool configChanged(false); + if (configuration.changed) configChanged = true; + for (auto& config : configuration.class_parameters_) { + if (config.second.changed) configChanged = true; + } + if (configChanged) { + throw std::runtime_error( + "Configuration has changed, models need to be trained."); + } + } + + /** + @brief Update training set for a specific label + @param label label of the sub-training set to update + @throws out_of_range if the label does not exist + */ + virtual void addModelForClass(std::string const& label) { + if (models.count(label) > 0 && models[label].isTraining()) + throw std::runtime_error("The Model is already training"); + + if (models.find(label) == models.end()) { + models.insert(std::pair<std::string, SingleClassModel>( + label, shared_parameters)); + models[label].training_events.addListener( + this, + &xmm::Model<SingleClassModel, ModelType>::onTrainingEvent); + models[label].label = label; + } + if (configuration.class_parameters_.count(label) > 0) { + models[label].parameters = configuration.class_parameters_[label]; + } else { + models[label].parameters = configuration; + } + } + + /** + @brief Training Threads + */ + std::map<std::string, std::thread> training_threads_; + + /** + @brief locks the Model while the models are training + Used in cancel method + */ + std::atomic<bool> cancel_required_; + + /** + @brief locks the Model while the models are training + Used in cancel method + */ + std::atomic<bool> is_training_; + + /** + @brief specifies if a thread for joining the training process has been + launched. + */ + std::atomic<bool> is_joining_; + + /** + @brief Number of models that are still training + */ + unsigned int models_still_training_; + + /** + @brief Mutex that prevents concurrent calls to onEvent() + */ + std::mutex event_mutex_; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelConfiguration.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelConfiguration.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c778264aef4b2a4953bae567a4441f39390bafa --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelConfiguration.hpp @@ -0,0 +1,226 @@ +/* + * xmmModelConfiguration.hpp + * + * Configuration for probabilistic models with multiple classes + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmModelConfiguration_h +#define xmmModelConfiguration_h + +#include "xmmModelParameters.hpp" +#include <map> + +namespace xmm { +/** + @brief Regression estimator for multiclass models + */ +enum class MultiClassRegressionEstimator { + /** + @brief the output is estimated as the output values of the likeliest class + */ + Likeliest = 0, + + /** + @brief the output is estimated as a weight sum of the output values of each + class + */ + Mixture = 1 +}; + +/** + @brief Multithreading mode for multiple-class training + */ +enum class MultithreadingMode { + /** + @brief No multithreading: all classes are trained sequentially + */ + Sequential, + + /** + @brief Multithreading: all classes are trained in parallel in different + threads. the train + function returns after all classes have finished training. + */ + Parallel, + + /** + @brief Multithreading in Background: all classes are trained in parallel in + different threads. the train + function returns after the training has started + @warning when the train function return, models are still training in + background. + */ + Background +}; + +/** + @ingroup Model + @brief Model configuration + @details The object contains both default parameters and class-specific + parameters + */ +template <typename ModelType> +class Configuration : public ClassParameters<ModelType> { + public: + template <typename SingleClassModel, typename ModelType_> + friend class Model; + + /** + @brief Default Constructor + */ + Configuration() + : multithreading(MultithreadingMode::Parallel), + multiClass_regression_estimator( + MultiClassRegressionEstimator::Likeliest) {} + + /** + @brief Copy Constructor + @param src Source Object + */ + Configuration(Configuration const& src) + : ClassParameters<ModelType>(src), + multithreading(src.multithreading), + multiClass_regression_estimator(src.multiClass_regression_estimator), + class_parameters_(src.class_parameters_) {} + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit Configuration(Json::Value const& root) { + ClassParameters<ModelType>::fromJson(root["default_parameters"]); + multithreading = static_cast<MultithreadingMode>( + root.get("multithreading", 0).asInt()); + multiClass_regression_estimator = + static_cast<MultiClassRegressionEstimator>( + root.get("multiClass_regression_estimator", 0).asInt()); + class_parameters_.clear(); + for (auto p : root["class_parameters"]) { + class_parameters_[p["label"].asString()].fromJson(p); + } + } + + /** + @brief Assignment + @param src Source Object + */ + Configuration& operator=(Configuration const& src) { + if (this != &src) { + ClassParameters<ModelType>::operator=(src); + class_parameters_ = src.class_parameters_; + multithreading = src.multithreading; + multiClass_regression_estimator = + src.multiClass_regression_estimator; + } + return *this; + } + + /** + @brief access the parameters of a given class by label + @details If the parameters have not been edited for this class yet, they + are set to the + default parameters. + @param label class label + @return a reference to the parameters of the given class + */ + ClassParameters<ModelType>& operator[](std::string label) { + if (class_parameters_.count(label) == 0) { + class_parameters_[label] = *this; + } + return class_parameters_[label]; + } + + /** + @brief Reset the parameters of all classes to default + */ + void reset() { class_parameters_.clear(); } + + /** + @brief Reset the parameters of a given classes to default + @param label class label + */ + void reset(std::string label) { + if (class_parameters_.count(label) > 0) { + class_parameters_.erase(label); + } + } + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const { + Json::Value root; + root["multithreading"] = static_cast<int>(multithreading); + root["multiClass_regression_estimator"] = + static_cast<int>(multiClass_regression_estimator); + root["default_parameters"] = ClassParameters<ModelType>::toJson(); + int i = 0; + for (auto p : class_parameters_) { + root["class_parameters"][i] = p.second.toJson(); + root["class_parameters"][i]["label"] = p.first; + i++; + } + return root; + } + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root) { + try { + Configuration<ModelType> tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } + } + + /** + @brief Multithreading Training Mode + */ + MultithreadingMode multithreading; + + /** + @brief Regression mode for multiple class (prediction from likeliest class + vs interpolation) + */ + MultiClassRegressionEstimator multiClass_regression_estimator; + + protected: + /** + @brief Parameters for each class + */ + std::map<std::string, ClassParameters<ModelType>> class_parameters_; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelParameters.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelParameters.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aec87523935c52a67a48bfa7a58fc97631a92e49 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelParameters.hpp @@ -0,0 +1,80 @@ +/* + * xmmModelParameters.hpp + * + * Model Parameters for each class (label) + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmModelParameters_h +#define xmmModelParameters_h + +#include "../common/xmmAttribute.hpp" +#include "../common/xmmJson.hpp" + +namespace xmm { +/** + @ingroup Model + @brief Class-specific Model Parameters. + @details this structure is then encapsulated in a Configuration object that + propagates default parameters + or class-specific parameters to the SingleClassModel. + */ +template <typename ModelType> +class ClassParameters : public Writable { + public: + /** + @brief Default Constructor + */ + ClassParameters() : changed(true) {} + + /** + @brief Copy Constructor + @param src Source Object + */ + ClassParameters(ClassParameters const& src) : changed(true) {} + + /** + @brief Constructor from Json Structure + @param root Json value + */ + explicit ClassParameters(Json::Value const& root) : changed(true) {} + + /** + @brief Assignment + @param src Source Object + */ + ClassParameters& operator=(ClassParameters const& src) { changed = true; } + + /** + @brief specifies if parameters have changed (model is invalid) + */ + bool changed; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelResults.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelResults.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c65fd38ce8b9b8610f49cb41243b00ab171bc7cd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelResults.hpp @@ -0,0 +1,125 @@ +/* + * xmmModelResults.hpp + * + * Results structures for probabilistic models + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmModelResults_h +#define xmmModelResults_h + +#include <string> +#include <vector> + +namespace xmm { +/** + @ingroup Model + @brief Class-specific Results of the filtering/inference process. + @details The default results contain both likelihoods for recognition + and vectors for the results of a regression + */ +template <typename ModelType> +struct ClassResults { + /** + @brief Instantaneous likelihood + */ + double instant_likelihood; + + /** + @brief Cumulative log-likelihood computed on a sliding window + */ + double log_likelihood; + + /** + @brief Predicted Output parameter vector (only used in regression mode) + @warning this variable is not allocated if the model is not bimodal + */ + std::vector<float> output_values; + + /** + @brief Predicted Output variance associated with the generated parameter + vector (only used in regression mode) + @warning this variable is not allocated if the model is not bimodal + */ + std::vector<float> output_covariance; +}; + +/** + @ingroup Model + @brief Results of the filtering/inference process (for a Model with multiple + classes). + @details The default results contain both likelihoods for recognition + and vectors for the results of a regression + */ +template <typename ModelType> +struct Results { + /** + @brief Instantaneous likelihood of each class + */ + std::vector<double> instant_likelihoods; + + /** + @brief Normalized instantaneous likelihood of each class + */ + std::vector<double> instant_normalized_likelihoods; + + /** + @brief Smoothed likelihood of each class + */ + std::vector<double> smoothed_likelihoods; + + /** + @brief Normalized smoothed likelihood of each class + */ + std::vector<double> smoothed_normalized_likelihoods; + + /** + @brief Cumulative smoothed log-likelihood of each class + */ + std::vector<double> smoothed_log_likelihoods; + + /** + @brief Label of the likeliest class + */ + std::string likeliest; + + /** + @brief Output values estimated by regression + @warning this variable is not allocated if the Model is not bimodal + */ + std::vector<float> output_values; + + /** + @brief Output variance over the values estimated by regression + @warning this variable is not allocated if the Model is not bimodal + */ + std::vector<float> output_covariance; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSharedParameters.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSharedParameters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21d74a834cf449f2a997d1dd07132155f22e1985 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSharedParameters.cpp @@ -0,0 +1,162 @@ +/* + * xmmModelSharedParameters.cpp + * + * Shared Parameters class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmModelSharedParameters.hpp" + +xmm::SharedParameters::SharedParameters() + : bimodal(false), + dimension((bimodal.get()) ? 2 : 1, (bimodal.get()) ? 2 : 1), + dimension_input((bimodal.get()) ? 1 : 0, 0, + (bimodal.get()) ? dimension.get() : 0), + em_algorithm_min_iterations(10, 1), + em_algorithm_max_iterations(0), + em_algorithm_percent_chg(0.01, 0.), + likelihood_window(1, 1) { + bimodal.onAttributeChange(this, &xmm::SharedParameters::onAttributeChange); + dimension.onAttributeChange(this, + &xmm::SharedParameters::onAttributeChange); + dimension_input.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + em_algorithm_min_iterations.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + em_algorithm_max_iterations.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + em_algorithm_percent_chg.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + likelihood_window.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + column_names.onAttributeChange(this, + &xmm::SharedParameters::onAttributeChange); +} + +xmm::SharedParameters::SharedParameters(SharedParameters const& src) + : bimodal(src.bimodal), + dimension(src.dimension), + dimension_input(src.dimension_input), + column_names(src.column_names), + em_algorithm_min_iterations(src.em_algorithm_min_iterations), + em_algorithm_max_iterations(src.em_algorithm_max_iterations), + em_algorithm_percent_chg(src.em_algorithm_percent_chg), + likelihood_window(src.likelihood_window) { + bimodal.onAttributeChange(this, &xmm::SharedParameters::onAttributeChange); + dimension.onAttributeChange(this, + &xmm::SharedParameters::onAttributeChange); + dimension_input.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + em_algorithm_min_iterations.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + em_algorithm_max_iterations.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + em_algorithm_percent_chg.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + likelihood_window.onAttributeChange( + this, &xmm::SharedParameters::onAttributeChange); + column_names.onAttributeChange(this, + &xmm::SharedParameters::onAttributeChange); +} + +xmm::SharedParameters::SharedParameters(Json::Value const& root) + : SharedParameters() { + bimodal.set(root.get("bimodal", false).asBool()); + dimension.set(root.get("dimension", bimodal.get() ? 2 : 1).asInt()); + dimension_input.set( + root.get("dimension_input", bimodal.get() ? 1 : 0).asInt()); + em_algorithm_min_iterations.set( + root.get("em_algorithm_min_iterations", 10).asInt()); + em_algorithm_max_iterations.set( + root.get("em_algorithm_max_iterations", 0).asInt()); + em_algorithm_percent_chg.set( + root.get("em_algorithm_percent_chg", 0.01).asFloat()); + likelihood_window.set(root.get("likelihood_window", 1).asInt()); + std::vector<std::string> tmpColNames(dimension.get()); + for (int i = 0; i < tmpColNames.size(); i++) + tmpColNames[i] = root["column_names"].get(i, "").asString(); + column_names.set(tmpColNames); +} + +xmm::SharedParameters& xmm::SharedParameters::operator=( + SharedParameters const& src) { + if (this != &src) { + bimodal = src.bimodal; + dimension = src.dimension; + dimension_input = src.dimension_input; + column_names = src.column_names; + em_algorithm_min_iterations = src.em_algorithm_min_iterations; + em_algorithm_max_iterations = src.em_algorithm_max_iterations; + em_algorithm_percent_chg = src.em_algorithm_percent_chg; + likelihood_window = src.likelihood_window; + } + return *this; +} + +Json::Value xmm::SharedParameters::toJson() const { + Json::Value root; + root["bimodal"] = bimodal.get(); + root["dimension"] = static_cast<int>(dimension.get()); + root["dimension_input"] = static_cast<int>(dimension_input.get()); + for (int i = 0; i < column_names.size(); i++) + root["column_names"][i] = column_names.at(i); + root["em_algorithm_min_iterations"] = em_algorithm_min_iterations.get(); + root["em_algorithm_max_iterations"] = em_algorithm_max_iterations.get(); + root["em_algorithm_percent_chg"] = em_algorithm_percent_chg.get(); + root["likelihood_window"] = static_cast<int>(likelihood_window.get()); + return root; +} + +void xmm::SharedParameters::fromJson(Json::Value const& root) { + try { + SharedParameters tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +void xmm::SharedParameters::onAttributeChange(AttributeBase* attr_pointer) { + if (attr_pointer == &bimodal) { + if (bimodal.get()) { + dimension.setLimitMin(2); + if (dimension.get() < 2) dimension.set(2); + dimension_input.setLimitMin(1); + if (dimension_input.get() < 1) dimension_input.set(1); + } else { + dimension.setLimitMin(1); + if (dimension.get() < 1) dimension.set(1); + dimension_input.setLimitMax(0); + dimension_input.set(0); + } + } else if (attr_pointer == &dimension) { + dimension_input.setLimitMax(dimension.get() - 1); + column_names.resize(dimension.get()); + } + attr_pointer->changed = false; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSharedParameters.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSharedParameters.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aa05ae5be89fd64fa13412d709c54750f7f00a9c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSharedParameters.hpp @@ -0,0 +1,160 @@ +/* + * xmmModelSharedParameters.hpp + * + * Shared Parameters class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmModelSharedParameters_h +#define xmmModelSharedParameters_h + +#include "../common/xmmEvents.hpp" +#include "../trainingset/xmmTrainingSet.hpp" +#include <mutex> + +namespace xmm { +/** + @defgroup Model [Core] Probabilistic Models + */ + +/** + @ingroup Model + @brief Shared Parameters for models with multiple classes. + @details This structure is shared by pointer between the class-specific models + to avoid + data duplication and ensures that all class-specific models share the same + common attributes. + */ +class SharedParameters : public Writable { + public: + template <typename SingleClassModel, typename ModelType> + friend class Model; + friend class SingleClassProbabilisticModel; + friend class SingleClassGMM; + friend class SingleClassHMM; + friend class HierarchicalHMM; + friend class GMM; + + /** + @brief Default Constructor + */ + SharedParameters(); + + /** + @brief Copy Constructor + @param src Source Object + */ + SharedParameters(SharedParameters const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit SharedParameters(Json::Value const& root); + + /** + @brief Assignment + @param src Source Object + */ + SharedParameters& operator=(SharedParameters const& src); + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root); + + ///@} + + /** + @brief defines if the phrase is bimodal (true) or unimodal (false) + */ + Attribute<bool> bimodal; + + /** + @brief total dimension of the training data + */ + Attribute<unsigned int> dimension; + + /** + @brief Dimension of the input modality + */ + Attribute<unsigned int> dimension_input; + + /** + @brief labels of the columns of input/output data (e.g. descriptor names) + */ + Attribute<std::vector<std::string>> column_names; + + /** + @brief Minimum number of iterations of the EM algorithm + */ + Attribute<unsigned int> em_algorithm_min_iterations; + + /** + @brief Maximum number of iterations of the EM algorithm. + @details If this value is superior to + minSteps, this criterion is used. Otherwise, only the + em_algorithm_percent_chg criterion applies. + */ + Attribute<unsigned int> em_algorithm_max_iterations; + + /** + @brief log-likelihood difference threshold necessary to stop the EM + algorithm. + @details When the percent-change in likelihood of the training data given + the + estimated parameters gets under this threshold, the EM algorithm is + stopped. + */ + Attribute<double> em_algorithm_percent_chg; + + /** + @brief Size of the window (in samples) used to compute the likelihoods + */ + Attribute<unsigned int> likelihood_window; + + protected: + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSingleClass.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSingleClass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28259e4072b140674178a0ee50224168a1d1e9cd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSingleClass.cpp @@ -0,0 +1,238 @@ +/* + * xmmModelSingleClass.hpp + * + * Abstract class for Single-class Probabilistic Machine learning models based + * on the EM algorithm + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmModelSingleClass.hpp" +#include <cmath> + +#pragma mark - +#pragma mark Constructors +xmm::SingleClassProbabilisticModel::SingleClassProbabilisticModel( + std::shared_ptr<SharedParameters> p) + : label(""), + shared_parameters(p), + training_status(this, label), + is_training_(false), + cancel_training_(false) { + if (p == NULL) { + throw std::runtime_error( + "Cannot instantiate a probabilistic model without Shared " + "parameters."); + } + likelihood_buffer_.resize(shared_parameters->likelihood_window.get()); +} + +xmm::SingleClassProbabilisticModel::SingleClassProbabilisticModel( + SingleClassProbabilisticModel const& src) + : label(src.label), + shared_parameters(src.shared_parameters), + training_status(this, label), + is_training_(false), + cancel_training_(false) { + if (is_training_) + throw std::runtime_error("Cannot copy: target model is still training"); + if (src.is_training_) + throw std::runtime_error("Cannot copy: source model is still training"); +} + +xmm::SingleClassProbabilisticModel::SingleClassProbabilisticModel( + std::shared_ptr<SharedParameters> p, Json::Value const& root) + : label(""), + shared_parameters(p), + training_status(this, label), + is_training_(false), + cancel_training_(false) { + if (p == NULL) { + throw std::runtime_error( + "Cannot instantiate a probabilistic model without Shared " + "parameters."); + } + label = root["label"].asString(); + training_status.label = label; +} + +xmm::SingleClassProbabilisticModel& xmm::SingleClassProbabilisticModel:: +operator=(SingleClassProbabilisticModel const& src) { + if (this != &src) { + if (is_training_) + throw std::runtime_error( + "Cannot copy: target model is still training"); + if (src.is_training_) + throw std::runtime_error( + "Cannot copy: source model is still training"); + label = src.label; + training_status = TrainingEvent(this, label), + shared_parameters = src.shared_parameters; + is_training_ = false; + cancel_training_ = false; + } + return *this; +}; + +xmm::SingleClassProbabilisticModel::~SingleClassProbabilisticModel() { + while (this->isTraining()) { + } +} + +#pragma mark - +#pragma mark Accessors +bool xmm::SingleClassProbabilisticModel::isTraining() const { + return is_training_; +} + +#pragma mark - +#pragma mark Training +void xmm::SingleClassProbabilisticModel::train(TrainingSet* trainingSet) { + training_mutex_.lock(); + bool trainingError(false); + + training_status.status = TrainingEvent::Status::Run; + + if (trainingSet && !trainingSet->empty()) { + this->allocate(); + } else { + trainingError = true; + } + + if (cancelTrainingIfRequested()) return; + if (!trainingError) { + try { + this->emAlgorithmInit(trainingSet); + } catch (std::exception& e) { + trainingError = true; + } + } + + training_status.label = label; + training_status.log_likelihood = -std::numeric_limits<double>::max(); + training_status.iterations = 0; + double old_log_prob = training_status.log_likelihood; + + while (!emAlgorithmHasConverged(training_status.iterations, + training_status.log_likelihood, + old_log_prob)) { + if (cancelTrainingIfRequested()) return; + old_log_prob = training_status.log_likelihood; + if (!trainingError) { + try { + training_status.log_likelihood = + this->emAlgorithmUpdate(trainingSet); + } catch (std::exception& e) { + trainingError = true; + } + } + + if (std::isnan(100. * + fabs((training_status.log_likelihood - old_log_prob) / + old_log_prob)) && + (training_status.iterations > 1)) + trainingError = true; + + if (trainingError) { + is_training_ = false; + training_mutex_.unlock(); + training_status.status = TrainingEvent::Status::Error; + training_events.notifyListeners(training_status); + return; + } + + ++training_status.iterations; + + if (shared_parameters->em_algorithm_max_iterations.get() > + shared_parameters->em_algorithm_min_iterations.get()) + training_status.progression = + float(training_status.iterations) / + float(shared_parameters->em_algorithm_max_iterations.get()); + else + training_status.progression = + float(training_status.iterations) / + float(shared_parameters->em_algorithm_min_iterations.get()); + + training_events.notifyListeners(training_status); + } + + if (cancelTrainingIfRequested()) return; + this->emAlgorithmTerminate(); + + training_mutex_.unlock(); +} + +bool xmm::SingleClassProbabilisticModel::emAlgorithmHasConverged( + int step, double log_prob, double old_log_prob) const { + if (step >= 1000) return true; + if (shared_parameters->em_algorithm_max_iterations.get() >= + shared_parameters->em_algorithm_min_iterations.get()) + return (step >= shared_parameters->em_algorithm_max_iterations.get()); + else + return (step >= shared_parameters->em_algorithm_min_iterations.get()) && + (100. * fabs((log_prob - old_log_prob) / log_prob) <= + shared_parameters->em_algorithm_percent_chg.get()); +} + +void xmm::SingleClassProbabilisticModel::emAlgorithmTerminate() { + training_status.status = TrainingEvent::Status::Done; + training_events.notifyListeners(training_status); + this->is_training_ = false; +} + +void xmm::SingleClassProbabilisticModel::cancelTraining() { + if (isTraining()) { + cancel_training_ = true; + } +} + +bool xmm::SingleClassProbabilisticModel::cancelTrainingIfRequested() { + if (!cancel_training_) return false; + training_mutex_.unlock(); + training_status.label = label; + training_status.status = TrainingEvent::Status::Cancel; + training_events.notifyListeners(training_status); + is_training_ = false; + return true; +} + +#pragma mark - +#pragma mark Performance +void xmm::SingleClassProbabilisticModel::reset() { + check_training(); + likelihood_buffer_.resize(shared_parameters->likelihood_window.get()); + likelihood_buffer_.clear(); +} + +#pragma mark - +#pragma mark File IO +Json::Value xmm::SingleClassProbabilisticModel::toJson() const { + check_training(); + Json::Value root; + root["label"] = label; + return root; +} \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSingleClass.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSingleClass.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cad4a342725ea6c83043448283c83a9ddb3e9ad6 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/model/xmmModelSingleClass.hpp @@ -0,0 +1,372 @@ +/* + * xmmModelSingleClass.hpp + * + * Abstract class for Single-class Probabilistic Machine learning models based + * on the EM algorithm + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmModelSingleClass_h +#define xmmModelSingleClass_h + +#include "../common/xmmCircularbuffer.hpp" +#include "../common/xmmEvents.hpp" +#include "../trainingset/xmmTrainingSet.hpp" +#include "xmmModelSharedParameters.hpp" +#include <memory> +#include <mutex> + +namespace xmm { +/** + @ingroup Model + @brief Event for monitoring the training process + */ +class TrainingEvent { + public: + /** + @brief Status of the training process + */ + enum Status { + /** + @brief Training is still running + */ + Run, + + /** + @brief An error occured during training + */ + Error, + + /** + @brief The training has been cancelled. + */ + Cancel, + + /** + @brief Training is done without error + */ + Done, + + /** + @brief The training of all classes has finished + */ + Alldone + }; + + /** + @brief Type of Training Error + */ + enum class ErrorType { + /** + @brief Convergence Errors (numerical errors in the training process). + @details these errors can be due to issues with the training data (e.g. + nan values), or + bad choice of parameters (e.g. regularization too low). + */ + ConvergenceError + }; + + /** + @brief Constructor + @param model_ Source model + @param label_ Label of the model sending the notification + @param status_ status of the training process + */ + TrainingEvent(void* model_, std::string label_, + Status status_ = Status::Run) + : model(model_), + label(label_), + status(status_), + progression(0), + log_likelihood(0), + iterations(0) {} + + /** + @brief Copy constructor + @param src source event + */ + TrainingEvent(TrainingEvent const& src) + : model(src.model), + label(src.label), + status(src.status), + progression(src.progression), + log_likelihood(src.log_likelihood), + iterations(src.iterations) {} + + /** + @brief Assignment operator + @param src source event + */ + TrainingEvent& operator=(TrainingEvent const& src) { + if (this != &src) { + model = src.model; + label = src.label; + status = src.status; + progression = src.progression; + log_likelihood = src.log_likelihood; + iterations = src.iterations; + } + return *this; + } + + /** + @brief Source Model + */ + void* model; + + /** + @brief Label of the source model, if any. + */ + std::string label; + + /** + @brief Status of the training process + */ + Status status; + + /** + @brief progression within the training algorithm + */ + float progression; + + /** + @brief Log-likelihood of the data given the model's parameters at the en of + training + */ + double log_likelihood; + + /** + @brief Number of EM iterations + */ + double iterations; +}; + +/** + @ingroup Model + @brief Generic Template for Machine Learning Probabilistic models based on the + EM algorithm + */ +class SingleClassProbabilisticModel : public Writable { + public: + /** + @brief Constructor + @param p pointer to a shared parameters object (owned by a Model) + */ + SingleClassProbabilisticModel(std::shared_ptr<SharedParameters> p = NULL); + + /** + @brief Copy Constructor + @param src Source Model + */ + SingleClassProbabilisticModel(SingleClassProbabilisticModel const& src); + + /** + @brief Constructor from Json + @param p pointer to a shared parameters object (owned by a Model) + @param root Json structure + */ + explicit SingleClassProbabilisticModel(std::shared_ptr<SharedParameters> p, + Json::Value const& root); + + /** + @brief Assignment + @param src Source Model + */ + SingleClassProbabilisticModel& operator=( + SingleClassProbabilisticModel const& src); + + /** + @brief Destructor + */ + virtual ~SingleClassProbabilisticModel(); + + /** @name Training */ + ///@{ + + /** + @brief Checks if the model is training + @return true if the model is training + */ + bool isTraining() const; + + /** + @brief Main training method based on the EM algorithm + @details the method performs a loop over the pure virtual method + emAlgorithmUpdate() until convergence. + The @a emAlgorithmUpdate method computes both E and M steps of the EM + algorithm. + @param trainingSet Training Set to train the model. + @see emAlgorithmUpdate + */ + void train(TrainingSet* trainingSet); + + /** + @brief Cancels the training process : sets a flag so that the training + stops at the next + possible exit in the training process. + @warning the model is still training when this function returns. This + function only requests the training + process to cancel. + */ + void cancelTraining(); + + ///@} + + /** @name Performance */ + ///@{ + + /** + @brief Resets the fitering process (recognition or regression) + */ + virtual void reset(); + + /** + @brief filters a incoming observation (performs recognition or regression) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + @return likelihood of the observation + */ + virtual double filter(std::vector<float> const& observation) = 0; + + ///@} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root) = 0; + + ///@} + + /** + @brief label associated with the given model + */ + std::string label; + + /** + @brief Pointer to the shared parameters owned by a multi-class model + */ + std::shared_ptr<SharedParameters> shared_parameters; + + /** + @brief Generator for events monitoring the training process + */ + EventGenerator<TrainingEvent> training_events; + + /** + @brief Event containing information on the current status of the training + process + */ + TrainingEvent training_status; + + protected: + /** + @brief Allocate memory for the model's parameters + @details called when dimensions are modified + */ + virtual void allocate() = 0; + + /** + @brief Initialize the training algorithm + */ + virtual void emAlgorithmInit(TrainingSet* trainingSet) = 0; + + /** + @brief Update Method of the EM algorithm + @details performs E and M steps of the EM algorithm. + @return likelihood of the training data given the current model parameters + (before re-estimation). + */ + virtual double emAlgorithmUpdate(TrainingSet* trainingSet) = 0; + + /** + @brief Terminate the training algorithm + */ + virtual void emAlgorithmTerminate(); + + /** + @brief checks if the training has converged according to the object's EM + stop criterion + @param step index of the current step of the EM algorithm + @param log_prob log-likelihood returned by the EM update + @param old_log_prob log-likelihood returned by the EM update at the + previous step + */ + bool emAlgorithmHasConverged(int step, double log_prob, + double old_log_prob) const; + + /** + @brief checks if a cancel request has been sent and accordingly cancels the + training process + @return true if the training has been canceled. + */ + bool cancelTrainingIfRequested(); + + /** + @brief Checks if the model is still training + @throws runtime_error if the model is training. + */ + inline void check_training() const { + if (this->isTraining()) + throw std::runtime_error("The model is training"); + } + + /** + @brief Likelihood buffer used for smoothing + */ + CircularBuffer<double> likelihood_buffer_; + + /** + @brief Mutex used in Concurrent Mode + */ + std::mutex training_mutex_; + + /** + @brief defines if the model is being trained. + */ + bool is_training_; + + /** + @brief defines if the model received a request to cancel training + */ + bool cancel_training_; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmPhrase.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmPhrase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba9d79c8a0caa62b934364d7efcc3503f0092875 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmPhrase.cpp @@ -0,0 +1,582 @@ +/* + * xmmPhrase.cpp + * + * Multimodal data phrase + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmPhrase.hpp" +#include <limits> +#include <algorithm> + +xmm::Phrase::Phrase(MemoryMode memoryMode, Multimodality multimodality) + : own_memory_(memoryMode == MemoryMode::OwnMemory), + bimodal_(multimodality == Multimodality::Bimodal), + empty_(true), + length_(0), + input_length_(0), + output_length_(0), + max_length_(0) { + dimension.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + dimension_input.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + label.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + dimension.setLimitMin((bimodal_) ? 2 : 1); + dimension.set((bimodal_) ? 2 : 1, true); + dimension_input.setLimits((bimodal_) ? 1 : 0, (bimodal_) ? 2 : 0); + dimension_input.set((bimodal_) ? 1 : 0, true); + data_ = new float*[bimodal_ ? 2 : 1]; + data_[0] = NULL; + if (bimodal_) data_[1] = NULL; +} + +xmm::Phrase::Phrase(Phrase const& src) + : dimension(src.dimension), + dimension_input(src.dimension_input), + label(src.label), + column_names(src.column_names), + own_memory_(src.own_memory_), + bimodal_(src.bimodal_), + empty_(src.empty_), + length_(src.length_), + input_length_(src.input_length_), + output_length_(src.output_length_), + max_length_(src.max_length_) { + if (own_memory_) { + data_ = new float*[bimodal_ ? 2 : 1]; + if (max_length_ > 0) { + unsigned int modality_dim = + bimodal_ ? dimension_input.get() : dimension.get(); + data_[0] = new float[max_length_ * modality_dim]; + std::copy(src.data_[0], src.data_[0] + max_length_ * modality_dim, + data_[0]); + if (bimodal_) { + modality_dim = dimension.get() - dimension_input.get(); + data_[1] = new float[max_length_ * modality_dim]; + std::copy(src.data_[1], + src.data_[1] + max_length_ * modality_dim, data_[1]); + } + } + } else { + data_[0] = src.data_[0]; + if (bimodal_) data_[1] = src.data_[1]; + } + dimension.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + dimension_input.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + label.onAttributeChange(this, &xmm::Phrase::onAttributeChange); +} + +xmm::Phrase::Phrase(Json::Value const& root) + : own_memory_(true), + bimodal_(false), + empty_(true), + length_(0), + input_length_(0), + output_length_(0), + max_length_(0) { + if (!own_memory_) + throw std::runtime_error("Cannot read Phrase with Shared memory"); + + dimension.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + dimension_input.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + label.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + + bimodal_ = root.get("bimodal", false).asBool(); + dimension.setLimitMin((bimodal_) ? 2 : 1); + dimension_input.setLimits((bimodal_) ? 1 : 0, (bimodal_) ? 2 : 0); + dimension.set(root.get("dimension", bimodal_ ? 2 : 1).asInt(), true); + dimension_input.set(root.get("dimension_input", bimodal_ ? 1 : 0).asInt(), + true); + data_ = new float*[bimodal_ ? 2 : 1]; + data_[0] = NULL; + if (bimodal_) data_[1] = NULL; + + column_names.resize(dimension.get(), ""); + for (int i = 0; i < root["column_names"].size(); i++) { + column_names[i] = root["column_names"].get(i, "").asString(); + } + + label.set(root["label"].asString()); + + length_ = static_cast<unsigned int>(root.get("length", 0).asInt()); + max_length_ = length_; + input_length_ = length_; + output_length_ = length_; + empty_ = (length_ == 0 && input_length_ == 0 && output_length_ == 0); + + if (bimodal_) { + data_[0] = + reallocate<float>(data_[0], max_length_ * dimension_input.get(), + length_ * dimension_input.get()); + data_[1] = reallocate<float>( + data_[1], max_length_ * (dimension.get() - dimension_input.get()), + length_ * (dimension.get() - dimension_input.get())); + json2array(root["data_input"], data_[0], + length_ * dimension_input.get()); + json2array(root["data_output"], data_[1], + length_ * (dimension.get() - dimension_input.get())); + } else { + data_[0] = reallocate<float>(data_[0], max_length_ * dimension.get(), + length_ * dimension.get()); + json2array(root["data"], data_[0], length_ * dimension.get()); + } +} + +xmm::Phrase& xmm::Phrase::operator=(Phrase const& src) { + if (this != &src) { + if (own_memory_) { + if (data_) { + if (bimodal_) try { + delete[] data_[1]; + } catch (std::exception& e) { + } + try { + delete[] data_[0]; + } catch (std::exception& e) { + } + } + try { + delete[] data_; + } catch (std::exception& e) { + } + data_ = NULL; + } + own_memory_ = src.own_memory_; + bimodal_ = src.bimodal_; + empty_ = src.empty_; + dimension = src.dimension; + dimension_input = src.dimension_input; + max_length_ = src.max_length_; + length_ = src.length_; + input_length_ = src.input_length_; + output_length_ = src.output_length_; + column_names = src.column_names; + label = src.label; + + if (own_memory_) { + data_ = new float*[bimodal_ ? 2 : 1]; + if (max_length_ > 0) { + unsigned int modality_dim = + bimodal_ ? dimension_input.get() : dimension.get(); + data_[0] = new float[max_length_ * modality_dim]; + std::copy(src.data_[0], + src.data_[0] + max_length_ * modality_dim, data_[0]); + if (bimodal_) { + modality_dim = dimension.get() - dimension_input.get(); + data_[1] = new float[max_length_ * modality_dim]; + std::copy(src.data_[1], + src.data_[1] + max_length_ * modality_dim, + data_[1]); + } + } + } else { + data_[0] = src.data_[0]; + if (bimodal_) data_[1] = src.data_[1]; + } + dimension.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + dimension_input.onAttributeChange(this, + &xmm::Phrase::onAttributeChange); + label.onAttributeChange(this, &xmm::Phrase::onAttributeChange); + } + return *this; +} + +xmm::Phrase::~Phrase() { + if (own_memory_) { + if (bimodal_) { + delete[] data_[1]; + } + delete[] data_[0]; + } + delete[] data_; +} + +bool xmm::Phrase::ownMemory() const { return own_memory_; } + +bool xmm::Phrase::bimodal() const { return bimodal_; } + +unsigned int xmm::Phrase::size() const { return length_; } + +unsigned int xmm::Phrase::inputSize() const { return input_length_; } + +unsigned int xmm::Phrase::outputSize() const { return output_length_; } + +bool xmm::Phrase::empty() const { return empty_; } + +float xmm::Phrase::getValue(unsigned int index, unsigned int dim) const { + if (dim >= dimension.get()) + throw std::out_of_range("Phrase: dimension out of bounds"); + if (bimodal_) { + if (dim < dimension_input.get()) { + if (index >= input_length_) + throw std::out_of_range("Phrase: index out of bounds"); + return data_[0][index * dimension_input.get() + dim]; + } else { + if (index >= output_length_) + throw std::out_of_range("Phrase: index out of bounds"); + return data_[1][index * (dimension.get() - dimension_input.get()) + + dim - dimension_input.get()]; + } + } else { + if (index >= length_) + throw std::out_of_range("Phrase: index out of bounds"); + return data_[0][index * dimension.get() + dim]; + } +} + +float* xmm::Phrase::getPointer(unsigned int index) const { + if (index >= length_) + throw std::out_of_range("Phrase: index out of bounds"); + if (bimodal_) + throw std::runtime_error( + "this phrase is bimodal_, use 'get_dataPointer_input' and " + "'get_dataPointer_output'"); + return data_[0] + index * dimension.get(); +} + +float* xmm::Phrase::getPointer_input(unsigned int index) const { + if (index >= length_) + throw std::out_of_range("Phrase: index out of bounds"); + if (!bimodal_) + throw std::runtime_error( + "this phrase is unimodal, use 'get_dataPointer'"); + return data_[0] + index * dimension_input.get(); +} + +float* xmm::Phrase::getPointer_output(unsigned int index) const { + if (index >= length_) + throw std::out_of_range("Phrase: index out of bounds"); + if (!bimodal_) + throw std::runtime_error( + "this phrase is unimodal, use 'get_dataPointer'"); + return data_[1] + index * (dimension.get() - dimension_input.get()); +} + +void xmm::Phrase::connect(float* pointer_to_data, unsigned int length) { + if (own_memory_) + throw std::runtime_error("Cannot connect a phrase with own data"); + if (bimodal_) + throw std::runtime_error( + "Cannot connect a single array, use 'connect_input' and " + "'connect_output'"); + + data_[0] = pointer_to_data; + input_length_ = length; + length_ = length; + empty_ = false; +} + +void xmm::Phrase::connect(float* pointer_to_data_input, + float* pointer_to_data_output, unsigned int length) { + if (own_memory_) + throw std::runtime_error("Cannot connect a phrase with own data"); + if (!bimodal_) + throw std::runtime_error("This phrase is unimodal, use 'connect'"); + + data_[0] = pointer_to_data_input; + data_[1] = pointer_to_data_output; + input_length_ = length; + output_length_ = length; + trim(); + empty_ = false; +} + +void xmm::Phrase::connect_input(float* pointer_to_data, unsigned int length) { + if (own_memory_) + throw std::runtime_error("Cannot connect a phrase with own data"); + if (!bimodal_) + throw std::runtime_error("This phrase is unimodal, use 'connect'"); + + data_[0] = pointer_to_data; + input_length_ = length; + trim(); + empty_ = false; +} + +void xmm::Phrase::connect_output(float* pointer_to_data, unsigned int length) { + if (own_memory_) + throw std::runtime_error("Cannot connect a phrase with own data"); + if (!bimodal_) + throw std::runtime_error("This phrase is unimodal, use 'connect'"); + + data_[1] = pointer_to_data; + output_length_ = length; + trim(); + empty_ = false; +} + +void xmm::Phrase::disconnect() { + if (own_memory_) + throw std::runtime_error("Cannot disconnect a phrase with own data"); + data_[0] = NULL; + if (bimodal_) data_[1] = NULL; + length_ = 0; + input_length_ = 0; + output_length_ = 0; + empty_ = true; +} + +void xmm::Phrase::record(std::vector<float> const& observation) { + if (!own_memory_) + throw std::runtime_error("Cannot record in shared data phrase"); + if (bimodal_ && input_length_ != output_length_) + throw std::runtime_error( + "Cannot record bimodal_ phrase in synchronous mode: modalities " + "have different length"); + if (observation.size() != dimension.get()) + throw std::invalid_argument("Observation has wrong dimension"); + + if (length_ >= max_length_ || max_length_ == 0) { + reallocateLength(); + } + + if (bimodal_) { + copy(observation.begin(), observation.begin() + dimension_input.get(), + data_[0] + input_length_ * dimension_input.get()); + copy(observation.begin() + dimension_input.get(), + observation.begin() + dimension.get(), + data_[1] + + output_length_ * (dimension.get() - dimension_input.get())); + input_length_++; + output_length_++; + } else { + copy(observation.begin(), observation.end(), + data_[0] + length_ * dimension.get()); + input_length_++; + } + + length_++; + empty_ = false; +} + +void xmm::Phrase::record_input(std::vector<float> const& observation) { + if (!own_memory_) + throw std::runtime_error("Cannot record in shared data phrase"); + if (!bimodal_) + throw std::runtime_error("this phrase is unimodal, use 'record'"); + if (observation.size() != dimension_input.get()) + throw std::invalid_argument("Observation has wrong dimension"); + + if (input_length_ >= max_length_ || max_length_ == 0) { + reallocateLength(); + } + + copy(observation.begin(), observation.end(), + data_[0] + input_length_ * dimension_input.get()); + input_length_++; + trim(); + empty_ = false; +} + +void xmm::Phrase::record_output(std::vector<float> const& observation) { + if (!own_memory_) + throw std::runtime_error("Cannot record in shared data phrase"); + if (!bimodal_) + throw std::runtime_error("this phrase is unimodal, use 'record'"); + + if (observation.size() != dimension.get() - dimension_input.get()) + throw std::invalid_argument("Observation has wrong dimension"); + + if (output_length_ >= max_length_ || max_length_ == 0) { + reallocateLength(); + } + + copy(observation.begin(), observation.end(), + data_[1] + output_length_ * (dimension.get() - dimension_input.get())); + output_length_++; + trim(); + empty_ = false; +} + +void xmm::Phrase::clear() { + if (!own_memory_) + throw std::runtime_error("Cannot clear a shared data phrase"); + + length_ = 0; + input_length_ = 0; + output_length_ = 0; + empty_ = true; +} + +void xmm::Phrase::clearInput() { + if (!own_memory_) + throw std::runtime_error("Cannot clear a shared data phrase"); + if (!bimodal_) length_ = 0; + input_length_ = 0; + trim(); +} + +void xmm::Phrase::clearOutput() { + if (!own_memory_) + throw std::runtime_error("Cannot clear a shared data phrase"); + if (!bimodal_) length_ = 0; + output_length_ = 0; + trim(); +} + +Json::Value xmm::Phrase::toJson() const { + Json::Value root; + root["bimodal"] = bimodal_; + root["dimension"] = static_cast<int>(dimension.get()); + root["dimension_input"] = static_cast<int>(dimension_input.get()); + root["length"] = static_cast<int>(length_); + root["label"] = label.get(); + for (int i = 0; i < column_names.size(); i++) + root["column_names"][i] = column_names[i]; + if (bimodal_) { + root["data_input"] = + array2json(data_[0], length_ * dimension_input.get()); + root["data_output"] = array2json( + data_[1], length_ * (dimension.get() - dimension_input.get())); + } else { + root["data"] = array2json(data_[0], length_ * dimension.get()); + } + return root; +} + +void xmm::Phrase::fromJson(Json::Value const& root) { + try { + Phrase tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +std::vector<float> xmm::Phrase::mean() const { + std::vector<float> mean(dimension.get()); + for (unsigned int d = 0; d < dimension.get(); d++) { + mean[d] = 0.; + for (unsigned int t = 0; t < length_; t++) { + mean[d] += getValue(t, d); + } + mean[d] /= float(length_); + } + return mean; +} + +std::vector<float> xmm::Phrase::standardDeviation() const { + std::vector<float> stddev(dimension.get()); + std::vector<float> _mean = mean(); + for (unsigned int d = 0; d < dimension.get(); d++) { + stddev[d] = 0.; + for (unsigned int t = 0; t < length_; t++) { + stddev[d] += + (getValue(t, d) - _mean[d]) * (getValue(t, d) - _mean[d]); + } + stddev[d] /= float(length_); + stddev[d] = sqrtf(stddev[d]); + } + return stddev; +} + +std::vector<std::pair<float, float>> xmm::Phrase::minmax() const { + std::vector<std::pair<float, float>> minmax( + dimension.get(), {std::numeric_limits<float>::max(), + std::numeric_limits<float>::lowest()}); + for (unsigned int d = 0; d < dimension.get(); d++) { + for (unsigned int t = 0; t < length_; t++) { + minmax[d].first = std::min(getValue(t, d), minmax[d].first); + minmax[d].second = std::max(getValue(t, d), minmax[d].second); + } + } + return minmax; +} + +void xmm::Phrase::rescale(std::vector<float> offset, std::vector<float> gain) { + for (int t = 0; t < size(); t++) { + float* p; + if (bimodal_) { + p = getPointer_input(t); + for (int d = 0; d < dimension_input.get(); d++) { + p[d] -= offset[d]; + p[d] *= gain[d]; + } + p = getPointer_output(t); + for (int d = dimension_input.get(); d < dimension.get(); d++) { + p[d] -= offset[d]; + p[d] *= gain[d]; + } + } else { + p = getPointer(t); + for (int d = 0; d < dimension.get(); d++) { + p[d] -= offset[d]; + p[d] *= gain[d]; + } + } + } +} + +void xmm::Phrase::trim() { + if (bimodal_) { + length_ = std::min(input_length_, output_length_); + empty_ = std::max(input_length_, output_length_) == 0; + } +} + +void xmm::Phrase::reallocateLength() { + unsigned int modality_dim = + bimodal_ ? dimension_input.get() : dimension.get(); + data_[0] = + reallocate<float>(data_[0], max_length_ * modality_dim, + (max_length_ + AllocationBlockSize) * modality_dim); + if (bimodal_) { + modality_dim = dimension.get() - dimension_input.get(); + data_[1] = reallocate<float>( + data_[1], max_length_ * modality_dim, + (max_length_ + AllocationBlockSize) * modality_dim); + } + max_length_ += AllocationBlockSize; +} + +void xmm::Phrase::onAttributeChange(xmm::AttributeBase* attr_pointer) { + if (attr_pointer == &dimension || attr_pointer == &dimension_input) { + length_ = 0; + input_length_ = 0; + output_length_ = 0; + max_length_ = 0; + empty_ = true; + if (own_memory_) { + delete data_[0]; + } + data_[0] = nullptr; + if (bimodal_) { + if (own_memory_) { + data_[1] = nullptr; + } + delete data_[1]; + } + column_names.resize(dimension.get()); + } + if (attr_pointer == &dimension) + dimension_input.setLimitMax(dimension.get() - 1); + if (attr_pointer == &label) { + PhraseEvent event(this, PhraseEvent::Type::LabelChanged); + events.notifyListeners(event); + } + attr_pointer->changed = false; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmPhrase.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmPhrase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..225c318d02650bd9f127cd471a77fb42a468d156 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmPhrase.hpp @@ -0,0 +1,542 @@ +/* + * xmmPhrase.hpp + * + * Multimodal data phrase + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmPhrase_h +#define xmmPhrase_h + +#include "../common/xmmAttribute.hpp" +#include "../common/xmmEvents.hpp" +#include "../common/xmmJson.hpp" +#include <cmath> + +namespace xmm { +/** + @defgroup TrainingSet [Core] Training Sets + */ + +/** + @ingroup TrainingSet + @brief Type of memory management for training sets and phrases + */ +enum class MemoryMode { + /** + @brief memory is owned by the Phrase container. + @details Phrases can be recorded directly + */ + OwnMemory, + + /** + @brief memory is shared with other data structures + @details Phrases can be 'connected' to external data arrays + */ + SharedMemory +}; + +/** + @ingroup TrainingSet + @brief Number of modalities in the data phrase + */ +enum class Multimodality { + /** + @brief single modality (i.e. 1 data array) + @details can be used for recognition + */ + Unimodal, + + /** + @brief two modalities (i.e. 2 data arrays) + @details can be used for regression (input/output) + */ + Bimodal +}; + +class Phrase; + +/** + @ingroup TrainingSet + @brief Event that can be thrown by a phrase to a training set + */ +class PhraseEvent { + public: + /** + @brief Type of event + */ + enum class Type { + /** + @brief Thrown when the label if the phrase is modified. + */ + LabelChanged, + }; + + /** + @brief Default constructor + @param phrase_ pointer to the source phrase + @param type_ type of event + */ + PhraseEvent(Phrase* phrase_, Type type_) : phrase(phrase_), type(type_) {} + + /** + @brief Copy constructor + @param src source event + */ + PhraseEvent(PhraseEvent const& src) : phrase(src.phrase), type(src.type) {} + + /** + @brief pointer to the source phrase + */ + Phrase* phrase; + + /** + @brief Type of event + */ + Type type; +}; + +/** + @ingroup TrainingSet + @brief Data phrase + @details The Phrase class can be used to store unimodal and Bimodal data + phrases. + It can have an autonomous memory, or this memory can be shared with another + data + container. These attributes are specified at construction. + */ +class Phrase : public Writable { + public: + friend class TrainingSet; + + /** + @brief Constructor + @param memoryMode Memory mode (owned vs shared) + @param multimodality Number of modalities + */ + Phrase(MemoryMode memoryMode = MemoryMode::OwnMemory, + Multimodality multimodality = Multimodality::Unimodal); + + /** + @brief Copy Constructor + @param src source Phrase + */ + Phrase(Phrase const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit Phrase(Json::Value const& root); + + /** + @brief Assignment + @param src source Phrase + */ + Phrase& operator=(Phrase const& src); + + /** + @brief Destructor. + @details Data is only deleted if the memory is owned (construction with + MemoryMode::OwnMemory) + */ + virtual ~Phrase(); + + /** @name Accessors */ + ///@{ + + /** + @brief checks if the training set is owns the data + @return true if the training set owns data (construction with + MemoryMode::OwnMemory) + */ + bool ownMemory() const; + + /** + @brief checks if the training set is bimodal + @return true if the training set is bimodal (construction with + Multimodality::Bimodal) + */ + bool bimodal() const; + + ///@} + + /** @name Access Data */ + ///@{ + + /** + @brief get the number of frames in the phrase + @return the number of frames in the phrase + */ + unsigned int size() const; + + /** + @brief get the number of frames in the input array of the phrase + @return the number of frames in the input array of the phrase + */ + unsigned int inputSize() const; + + /** + @brief get the number of frames in the output array of the phrase + @return the number of frames in the output array of the phrase + */ + unsigned int outputSize() const; + + /** + @brief check if the phrase is empty + @return true if the phrase is empty (length 0) + */ + bool empty() const; + + /** + @brief Access data at a given time index and dimension. + @param index time index + @param dim dimension considered, indexed from 0 to the total dimension of + the data across modalities + @throws out_of_range if time index or dimension are out of bounds + */ + float getValue(unsigned int index, unsigned int dim) const; + + /** + @brief Get pointer to the data at a given time index + @param index time index + @warning this method can be used only for unimodal phrases (construction + with Multimodality::Unimodal) + @throws out_of_range if time index is out of bounds + @throws runtime_error if the phrase is bimodal (construction with + Multimodality::Bimodal) + @return pointer to the data array of the modality, for the given time index + */ + float* getPointer(unsigned int index) const; + + /** + @brief Get pointer to the data at a given time index for the input modality + @warning this method can be used only for bimodal phrases (construction + with Multimodality::Bimodal) + @param index time index + @throws out_of_range if time index is out of bounds + @throws runtime_error if the phrase is unimodal (construction with + Multimodality::Unimodal) + @return pointer to the data array of the modality, for the given time index + */ + float* getPointer_input(unsigned int index) const; + + /** + @brief Get pointer to the data at a given time index for the output + modality + @warning this method can be used only for bimodal phrases (construction + with Multimodality::Bimodal) + @param index time index + @throws out_of_range if time index is out of bounds + @throws runtime_error if the phrase is unimodal (construction with + Multimodality::Unimodal) + @return pointer to the data array of the modality, for the given time index + */ + float* getPointer_output(unsigned int index) const; + + ///@} + + /** @name Connect (MemoryMode = SharedData) */ + ///@{ + + /** + @brief Connect a unimodal phrase to a shared container + @warning This method is only usable in Shared Memory (construction with + MemoryMode::SharedMemory) + @param pointer_to_data pointer to the data array + @param length length of the data array + @throws runtime_error if data is owned (construction with + MemoryMode::OwnMemory flag) + */ + void connect(float* pointer_to_data, unsigned int length); + + /** + @brief Connect a Bimodal phrase to a shared container + @warning This method is only usable in Shared Memory (construction with + MemoryMode::SharedMemory) + @param pointer_to_data_input pointer to the data array of the input + modality + @param pointer_to_data_output pointer to the data array of the output + modality + @param length length of the data array + @throws runtime_error if data is owned (construction with + MemoryMode::OwnMemory flag) + */ + void connect(float* pointer_to_data_input, float* pointer_to_data_output, + unsigned int length); + + /** + @brief Connect a Bimodal phrase to a shared container for the input + modality + @warning This method is only usable in Shared Memory (construction with + MemoryMode::SharedMemory) + @param pointer_to_data pointer to the data array of the input modality + @param length length of the data array + @throws runtime_error if data is owned (construction with + MemoryMode::OwnMemory flag) + */ + void connect_input(float* pointer_to_data, unsigned int length); + + /** + @brief Connect a Bimodal phrase to a shared container for the output + modality + @warning This method is only usable in Shared Memory (construction with + MemoryMode::SharedMemory) + @param pointer_to_data pointer to the data array of the output modality + @param length length of the data array + @throws runtime_error if data is owned (construction with + MemoryMode::OwnMemory flag) + */ + void connect_output(float* pointer_to_data, unsigned int length); + + /** + @brief Disconnect a phrase from a shared container + @warning This method is only usable in Shared Memory (construction with + MemoryMode::SharedMemory) + @throws runtime_error if data is owned (construction with + MemoryMode::OwnMemory flag) + */ + void disconnect(); + + ///@} + + /** @name Record (MemoryMode = OwnData) */ + ///@{ + + /** + @brief Record observation + @details Appends the observation vector observation to the data array.\n + This method is only usable in Own Memory (construction with + MemoryMode::OwnMemory) + @param observation observation vector (C-like array which must have the + size of the total + dimension of the data across all modalities) + @throws runtime_error if data is shared (construction with + MemoryMode::SharedMemory flag) + */ + void record(std::vector<float> const& observation); + + /** + @brief Record observation on input modality + Appends the observation vector observation to the data array\n + This method is only usable in Own Memory (construction with + MemoryMode::OwnMemory) + @param observation observation vector (C-like array which must have the + size of the total + dimension of the data across all modalities) + @throws runtime_error if data is shared (construction with + MemoryMode::SharedMemory flag) + */ + void record_input(std::vector<float> const& observation); + + /** + @brief Record observation on output modality + Appends the observation vector observation to the data array\n + This method is only usable in Own Memory (construction with + MemoryMode::OwnMemory) + @param observation observation vector (C-like array which must have the + size of the total + dimension of the data across all modalities) + @throws runtime_error if data is shared (construction with + MemoryMode::SharedMemory flag) + */ + void record_output(std::vector<float> const& observation); + + /** + @brief Reset length of the phrase to 0 ==> empty phrase\n + This method is only usable in Own Memory (construction with + MemoryMode::OwnMemory) + @throws runtime_error if data is shared (construction with + MemoryMode::SharedMemory flag) + @warning the memory is not released (only done in destructor). + */ + void clear(); + void clearInput(); + void clearOutput(); + + ///@} + + /** @name JSON I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + void fromJson(Json::Value const& root); + + ///@} + + /** @name Utilities */ + ///@{ + + /** + @brief Compute the mean of the data phrase along the time axis + @return mean of the phrase (along time axis, full-size) + */ + std::vector<float> mean() const; + + /** + @brief Compute the standard deviation of the data phrase along the time + axis + @return standard deviation of the phrase (along time axis, full-size) + */ + std::vector<float> standardDeviation() const; + + /** + @brief Compute the global min/max of the data phrase along the time axis + @return vector of min/max pairs ofthe phrases (along time axis, full-size) + */ + std::vector<std::pair<float, float>> minmax() const; + + /** + @brief rescale a phrase given an offset and gain + @param offset constant offset to be subtracted + @param gain gain to be applied + */ + void rescale(std::vector<float> offset, std::vector<float> gain); + + ///@} + + /** + @brief Total dimension of the phrase + */ + Attribute<unsigned int> dimension; + + /** + @brief Used in bimodal mode: dimension of the input modality. + */ + Attribute<unsigned int> dimension_input; + + /** + @brief Main label of the phrase + */ + Attribute<std::string> label; + + /** + @brief labels of the columns of the phrase (e.g. descriptor names) + */ + std::vector<std::string> column_names; + + protected: + /** + @brief trim phrase to minimal length of modalities + */ + void trim(); + + /** + @brief Memory Allocation + @details used record mode (no SHARED_MEMORY flag), the data vector is + reallocated + with a block size ALLOC_BLOCKSIZE + */ + void reallocateLength(); + + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); + + static const unsigned int AllocationBlockSize = 256; + + /** + @brief Defines if the phrase stores the data itself. + */ + bool own_memory_; + + /** + @brief Defines if the phrase is bimodal (true) or unimodal (false) + */ + bool bimodal_; + + /** + @brief true if the phrase does not contain any data + */ + bool empty_; + + /** + @brief Length of the phrase. If bimodal, it is the minimal length between + modalities + */ + unsigned int length_; + + /** + @brief Length of the array of the input modality + */ + unsigned int input_length_; + + /** + @brief Length of the array of the output modality + */ + unsigned int output_length_; + + /** + @brief Allocated length (only used in own memory mode) + */ + unsigned int max_length_; + + /** + @brief Pointer to the Data arrays + @details data has a size 1 in unimodal mode, 2 in bimodal mode. + */ + float** data_; + + EventGenerator<PhraseEvent> events; +}; + +/** + @brief Reallocate a C-like array (using c++ std::copy) + @param src source array + @param dim_src initial dimension + @param dim_dst target dimension + @return resized array (content is conserved) + */ +template <typename T> +T* reallocate(T* src, unsigned int dim_src, unsigned int dim_dst) { + T* dst = new T[dim_dst]; + + if (!src) return dst; + + if (dim_dst > dim_src) { + std::copy(src, src + dim_src, dst); + } else { + std::copy(src, src + dim_dst, dst); + } + delete[] src; + return dst; +} +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmTrainingSet.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmTrainingSet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0099ea4053aab523035eeb395eb69b95b2947081 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmTrainingSet.cpp @@ -0,0 +1,436 @@ +/* + * xmmTrainingSet.cpp + * + * Multimodal Training Set + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ +#include "xmmTrainingSet.hpp" +#include <limits> +#include <algorithm> + +xmm::TrainingSet::TrainingSet(MemoryMode memoryMode, + Multimodality multimodality) + : own_memory_(memoryMode == MemoryMode::OwnMemory), + bimodal_(multimodality == Multimodality::Bimodal) { + dimension.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + dimension_input.onAttributeChange(this, + &xmm::TrainingSet::onAttributeChange); + column_names.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + + dimension.setLimitMin((bimodal_) ? 2 : 1); + dimension.set((bimodal_) ? 2 : 1, true); + dimension_input.setLimits((bimodal_) ? 1 : 0, (bimodal_) ? 2 : 0); + dimension_input.set((bimodal_) ? 1 : 0, true); + column_names.resize(dimension.get()); +} + +xmm::TrainingSet::TrainingSet(TrainingSet const &src) + : dimension(src.dimension), + dimension_input(src.dimension_input), + column_names(src.column_names), + own_memory_(src.own_memory_), + bimodal_(src.bimodal_), + labels_(src.labels_), + phrases_(src.phrases_) { + dimension.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + dimension_input.onAttributeChange(this, + &xmm::TrainingSet::onAttributeChange); + column_names.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + for (auto phrase : src.phrases_) { + phrases_.insert(std::pair<int, std::shared_ptr<xmm::Phrase>>( + phrase.first, std::make_shared<Phrase>(*phrase.second))); + phrases_[phrase.first]->events.addListener( + this, &xmm::TrainingSet::onPhraseEvent); + } + update(); +} + +xmm::TrainingSet::TrainingSet(Json::Value const &root) + : own_memory_(true), bimodal_(false) { + if (!own_memory_) + throw std::runtime_error("Cannot read Training Set with Shared memory"); + + dimension.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + dimension_input.onAttributeChange(this, + &xmm::TrainingSet::onAttributeChange); + column_names.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + + bimodal_ = root.get("bimodal", false).asBool(); + + dimension.setLimitMin((bimodal_) ? 2 : 1); + dimension_input.setLimits((bimodal_) ? 1 : 0, (bimodal_) ? 2 : 0); + dimension.set(root.get("dimension", bimodal_ ? 2 : 1).asInt()); + dimension_input.set(root.get("dimension_input", bimodal_ ? 1 : 0).asInt()); + std::vector<std::string> tmpColNames(dimension.get()); + for (int i = 0; i < root["column_names"].size(); i++) { + tmpColNames[i] = root["column_names"].get(i, "").asString(); + } + column_names.set(tmpColNames); + + // Get Phrases + phrases_.clear(); + for (auto p : root["phrases"]) { + phrases_.insert(std::pair<int, std::shared_ptr<xmm::Phrase>>( + p["index"].asInt(), std::make_shared<Phrase>(p))); + phrases_[p["index"].asInt()]->events.addListener( + this, &xmm::TrainingSet::onPhraseEvent); + } + update(); +} + +xmm::TrainingSet &xmm::TrainingSet::operator=(TrainingSet const &src) { + if (this != &src) { + clear(); + own_memory_ = src.own_memory_; + bimodal_ = src.bimodal_; + dimension = src.dimension; + dimension_input = src.dimension_input; + column_names = src.column_names; + labels_ = src.labels_; + dimension.onAttributeChange(this, &xmm::TrainingSet::onAttributeChange); + dimension_input.onAttributeChange(this, + &xmm::TrainingSet::onAttributeChange); + column_names.onAttributeChange(this, + &xmm::TrainingSet::onAttributeChange); + for (auto phrase : src.phrases_) { + phrases_.insert(std::pair<int, std::shared_ptr<xmm::Phrase>>( + phrase.first, std::make_shared<Phrase>(*phrase.second))); + phrases_[phrase.first]->events.addListener( + this, &xmm::TrainingSet::onPhraseEvent); + } + update(); + } + return *this; +} + +xmm::TrainingSet::~TrainingSet() {} + +bool xmm::TrainingSet::ownMemory() const { return own_memory_; } + +bool xmm::TrainingSet::bimodal() const { return bimodal_; } + +bool xmm::TrainingSet::empty() const { return phrases_.empty(); } + +unsigned int xmm::TrainingSet::size() const { + return static_cast<unsigned int>(phrases_.size()); +} + +void xmm::TrainingSet::onAttributeChange(xmm::AttributeBase *attr_pointer) { + if (attr_pointer == &dimension) { + for (auto &phrase : phrases_) { + phrase.second->dimension.set(dimension.get()); + } + for (std::map<std::string, TrainingSet>::iterator it = + sub_training_sets_.begin(); + it != sub_training_sets_.end(); ++it) + it->second.dimension.set(dimension.get(), true); + + column_names.resize(dimension.get()); + dimension_input.setLimitMax(dimension.get() - 1); + } + if (attr_pointer == &dimension_input) { + for (auto &phrase : phrases_) { + phrase.second->dimension_input.set(dimension_input.get()); + } + for (std::map<std::string, TrainingSet>::iterator it = + sub_training_sets_.begin(); + it != sub_training_sets_.end(); ++it) + it->second.dimension_input.set(dimension_input.get(), true); + } + if (attr_pointer == &column_names) { + for (auto &phrase : phrases_) { + phrase.second->column_names = column_names.get(); + } + + for (std::map<std::string, TrainingSet>::iterator it = + sub_training_sets_.begin(); + it != sub_training_sets_.end(); ++it) + it->second.column_names.set(column_names.get(), true); + } + attr_pointer->changed = false; +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::iterator +xmm::TrainingSet::begin() { + return phrases_.begin(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::iterator xmm::TrainingSet::end() { + return phrases_.end(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::reverse_iterator +xmm::TrainingSet::rbegin() { + return phrases_.rbegin(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::reverse_iterator +xmm::TrainingSet::rend() { + return phrases_.rend(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::const_iterator +xmm::TrainingSet::cbegin() const { + return phrases_.cbegin(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::const_iterator +xmm::TrainingSet::cend() const { + return phrases_.cend(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::const_reverse_iterator +xmm::TrainingSet::crbegin() const { + return phrases_.crbegin(); +} + +std::map<int, std::shared_ptr<xmm::Phrase>>::const_reverse_iterator +xmm::TrainingSet::crend() const { + return phrases_.crend(); +} + +std::shared_ptr<xmm::Phrase> xmm::TrainingSet::getPhrase(int n) const { + if (phrases_.count(n) == 0) return nullptr; + return phrases_.at(n); +} + +void xmm::TrainingSet::addPhrase(int phraseIndex, std::string label) { + phrases_[phraseIndex] = std::make_shared<Phrase>( + own_memory_ ? MemoryMode::OwnMemory : MemoryMode::SharedMemory, + bimodal_ ? Multimodality::Bimodal : Multimodality::Unimodal); + phrases_[phraseIndex]->events.addListener(this, + &xmm::TrainingSet::onPhraseEvent); + phrases_[phraseIndex]->dimension.set(dimension.get()); + phrases_[phraseIndex]->dimension_input.set(dimension_input.get()); + phrases_[phraseIndex]->column_names = this->column_names.get(); + phrases_[phraseIndex]->label.set(label, true); + update(); +} + +void xmm::TrainingSet::addPhrase(int phraseIndex, Phrase const &phrase) { + phrases_[phraseIndex] = std::make_shared<Phrase>(phrase); + phrases_[phraseIndex]->events.removeListeners(); + phrases_[phraseIndex]->events.addListener(this, + &xmm::TrainingSet::onPhraseEvent); + update(); +} + +void xmm::TrainingSet::addPhrase(int phraseIndex, + std::shared_ptr<Phrase> phrase) { + phrases_[phraseIndex] = phrase; + phrases_[phraseIndex]->events.addListener(this, + &xmm::TrainingSet::onPhraseEvent); + update(); +} + +void xmm::TrainingSet::removePhrase(int phraseIndex) { + phrases_.erase(phraseIndex); + update(); +} + +void xmm::TrainingSet::removePhrasesOfClass(std::string const &label) { + bool contLoop(true); + while (contLoop) { + contLoop = false; + for (auto &phrase : phrases_) { + if (phrase.second->label.get() == label) { + removePhrase(phrase.first); + contLoop = true; + break; + } + } + } + update(); +} + +void xmm::TrainingSet::clear() { + sub_training_sets_.clear(); + phrases_.clear(); + labels_.clear(); +} + +xmm::TrainingSet *xmm::TrainingSet::getPhrasesOfClass( + std::string const &label) { + std::map<std::string, TrainingSet>::iterator it = + sub_training_sets_.find(label); + if (it == sub_training_sets_.end()) return nullptr; + return &(it->second); +} + +void xmm::TrainingSet::onPhraseEvent(PhraseEvent const &e) { + if (e.type == PhraseEvent::Type::LabelChanged) { + update(); + } +} + +void xmm::TrainingSet::update() { + labels_.clear(); + for (auto &phrase : phrases_) { + labels_.insert(phrase.second->label.get()); + } + sub_training_sets_.clear(); + for (std::string label : labels_) { + sub_training_sets_.insert(std::pair<std::string, TrainingSet>( + label, + {own_memory_ ? MemoryMode::OwnMemory : MemoryMode::SharedMemory, + bimodal_ ? Multimodality::Bimodal : Multimodality::Unimodal})); + sub_training_sets_[label].dimension.set(dimension.get()); + sub_training_sets_[label].dimension_input.set(dimension_input.get()); + sub_training_sets_[label].column_names = this->column_names; + // int newPhraseIndex(0); + for (auto &phrase : phrases_) { + if (phrase.second->label.get() == label) { + sub_training_sets_[label].phrases_[phrase.first] = + this->phrases_[phrase.first]; + // newPhraseIndex++; + } + } + } +} + +std::vector<float> xmm::TrainingSet::mean() const { + std::vector<float> mean(dimension.get(), 0.0); + unsigned int total_length(0); + for (auto &phrase : phrases_) { + for (unsigned int d = 0; d < dimension.get(); d++) { + for (unsigned int t = 0; t < phrase.second->size(); t++) { + mean[d] += phrase.second->getValue(t, d); + } + } + total_length += phrase.second->size(); + } + + for (unsigned int d = 0; d < dimension.get(); d++) + mean[d] /= float(total_length); + + return mean; +} + +std::vector<float> xmm::TrainingSet::standardDeviation() const { + std::vector<float> stddev(dimension.get()); + std::vector<float> _mean = mean(); + unsigned int total_length(0); + for (auto &phrase : phrases_) { + for (unsigned int d = 0; d < dimension.get(); d++) { + for (unsigned int t = 0; t < phrase.second->size(); t++) { + stddev[d] += (phrase.second->getValue(t, d) - _mean[d]) * + (phrase.second->getValue(t, d) - _mean[d]); + } + } + total_length += phrase.second->size(); + } + + for (unsigned int d = 0; d < dimension.get(); d++) { + stddev[d] /= float(total_length); + stddev[d] = sqrtf(stddev[d]); + } + + return stddev; +} + +std::vector<std::pair<float, float>> xmm::TrainingSet::minmax() const { + std::vector<std::pair<float, float>> minmax( + dimension.get(), {std::numeric_limits<float>::max(), + std::numeric_limits<float>::lowest()}); + if (bimodal_) { + for (auto &phrase : phrases_) { + for (unsigned int d = 0; d < dimension_input.get(); d++) { + for (unsigned int t = 0; t < phrase.second->inputSize(); t++) { + minmax[d].first = std::min(phrase.second->getValue(t, d), + minmax[d].first); + minmax[d].second = std::max(phrase.second->getValue(t, d), + minmax[d].second); + } + } + for (unsigned int d = dimension_input.get(); d < dimension.get(); + d++) { + for (unsigned int t = 0; t < phrase.second->outputSize(); t++) { + minmax[d].first = std::min(phrase.second->getValue(t, d), + minmax[d].first); + minmax[d].second = std::max(phrase.second->getValue(t, d), + minmax[d].second); + } + } + } + } else { + for (auto &phrase : phrases_) { + for (unsigned int d = 0; d < dimension.get(); d++) { + for (unsigned int t = 0; t < phrase.second->size(); t++) { + minmax[d].first = std::min(phrase.second->getValue(t, d), + minmax[d].first); + minmax[d].second = std::max(phrase.second->getValue(t, d), + minmax[d].second); + } + } + } + } + return minmax; +} + +void xmm::TrainingSet::rescale(std::vector<float> offset, + std::vector<float> gain) { + for (auto &phrase : phrases_) { + phrase.second->rescale(offset, gain); + } +} + +void xmm::TrainingSet::normalize() { + std::vector<float> offset = mean(); + std::vector<float> gain = standardDeviation(); + for (auto &v : gain) v = 1. / v; + rescale(offset, gain); +} + +Json::Value xmm::TrainingSet::toJson() const { + Json::Value root; + root["bimodal"] = bimodal_; + root["dimension"] = static_cast<int>(dimension.get()); + root["dimension_input"] = static_cast<int>(dimension_input.get()); + for (int i = 0; i < dimension.get(); i++) + root["column_names"][i] = column_names.at(i); + + // Add Phrases + root["phrases"].resize(static_cast<Json::ArrayIndex>(size())); + Json::ArrayIndex phraseIndex(0); + for (auto &phrase : phrases_) { + root["phrases"][phraseIndex] = phrase.second->toJson(); + root["phrases"][phraseIndex]["index"] = phrase.first; + phraseIndex++; + } + + return root; +} + +void xmm::TrainingSet::fromJson(Json::Value const &root) { + try { + TrainingSet tmp(root); + *this = tmp; + } catch (JsonException &e) { + throw e; + } +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmTrainingSet.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmTrainingSet.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6fa03c6cd1a9ace2e93ace67149ef3cbbae49846 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/core/trainingset/xmmTrainingSet.hpp @@ -0,0 +1,357 @@ +/* + * xmmTrainingSet.hpp + * + * Multimodal Training Set + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmTrainingSet_h +#define xmmTrainingSet_h + +#include "xmmPhrase.hpp" +#include <map> +#include <set> +#include <memory> + +namespace xmm { +/** + @ingroup TrainingSet + @brief Base class for the definition of training sets + @details Training sets host a collection of phrases + */ +class TrainingSet : public Writable { + public: + /** + @brief Constructor + @param memoryMode Memory mode (owned vs shared) + @param multimodality Number of modalities + */ + TrainingSet(MemoryMode memoryMode = MemoryMode::OwnMemory, + Multimodality multimodality = Multimodality::Unimodal); + + /** + @brief Copy Constructor + @param src source Training Set + */ + TrainingSet(TrainingSet const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit TrainingSet(Json::Value const& root); + + /** + @brief Assignment Operator + @param src source Training Set + */ + TrainingSet& operator=(TrainingSet const& src); + + /** + @brief Destructor + @warning phrases are only deleted if the training set is unlocked + @see lock() + */ + virtual ~TrainingSet(); + + /** @name Accessors */ + ///@{ + + /** + @brief checks if the training set is owns the data + @return true if the training set owns data (construction with + MemoryMode::OwnMemory) + */ + bool ownMemory() const; + + /** + @brief checks if the training set is bimodal + @return true if the training set is bimodal (construction with + Multimodality::Bimodal) + */ + bool bimodal() const; + + ///@} + + /** @name Manipulate Phrases */ + ///@{ + + /** + @brief checks if the training set is empty + @return true if the training set is empty (no training phrases) + */ + bool empty() const; + + /** + @brief Size of the training set + @return size of the training set (number of phrases) + */ + unsigned int size() const; + + /** + @brief iterator to the beginning of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::iterator begin(); + + /** + @brief iterator to the end of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::iterator end(); + + /** + @brief reverse iterator to the beginning of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::reverse_iterator rbegin(); + + /** + @brief reverse iterator to the end of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::reverse_iterator rend(); + + /** + @brief constant iterator to the beginning of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::const_iterator cbegin() const; + + /** + @brief constant iterator to the end of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::const_iterator cend() const; + + /** + @brief constant reverse iterator to the beginning of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::const_reverse_iterator + crbegin() const; + + /** + @brief constant reverse iterator to the end of phrases + */ + std::map<int, std::shared_ptr<xmm::Phrase>>::const_reverse_iterator crend() + const; + + /** + @brief add a new phrase, or reset the phrase if existing + @details The phrase is set to an empty phrase with the current attributes + (dimensions, etc). + The phrase is created if it does not exists at the given index. + @param phraseIndex index of the data phrase in the trainingSet + @param label Label of the phrase + */ + void addPhrase(int phraseIndex, std::string label = ""); + + /** + @brief add a new phrase, or reset the phrase if existing + @details The phrase is set to a copy of the phrase passed in argument + The phrase is created if it does not exists at the given index. + @param phraseIndex index of the data phrase in the trainingSet + @param phrase source phrase + */ + void addPhrase(int phraseIndex, Phrase const& phrase); + + /** + @brief add a new phrase, or reset the phrase if existing + @details The phrase is set to point to the existing phrase passed in + argument. + The phrase is created if it does not exists at the given index. + @param phraseIndex index of the data phrase in the trainingSet + @param phrase pointer to an existing phrase + */ + void addPhrase(int phraseIndex, std::shared_ptr<Phrase> phrase); + + /** + @brief delete a phrase + @warning if the training set is locked, the phrase iself is not deleted + (only the reference) + @param phraseIndex index of the phrase + @throws out_of_bounds if the phrase does not exist + */ + void removePhrase(int phraseIndex); + + /** + @brief delete all phrases of a given class + @warning if the training set is locked, the phrases themselves are not + deleted (only the references) + @param label label of the class to delete + @throws out_of_bounds if the label does not exist + */ + void removePhrasesOfClass(std::string const& label); + + /** + @brief Access Phrase by index + @param phraseIndex index of the phrase + @return pointer to the phrase if it exists, else nullptr + */ + std::shared_ptr<xmm::Phrase> getPhrase(int phraseIndex) const; + + /** + @brief get the pointer to the sub-training set containing all phrases with + a given label + @warning in order to protect the phrases in the current training set, the + sub-training set returned is locked + @param label target label + @return pointer to the sub-training set containing all phrases with a given + label + @throws out_of_range if the label does not exist + */ + TrainingSet* getPhrasesOfClass(std::string const& label); + + /** + @brief delete all phrases + @warning if the training set is locked, the phrases themselves are not + deleted (only their references) + */ + void clear(); + + /** + @brief get the list of labels currently in the training set + @return reference to the set of labels in the training set + */ + const std::set<std::string>& labels() const { return labels_; } + + ///@} + + /** @name JSON I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + void fromJson(Json::Value const& root); + + ///@} + + /** @name Utilities */ + ///@{ + + /** + @brief Compute the global mean of all data phrases along the time axis + @return global mean of all phrases (along time axis, full-size) + */ + std::vector<float> mean() const; + + /** + @brief Compute the global standard deviation of all data phrases along the + time axis + @return global standard deviation of all phrases (along time axis, + full-size) + */ + std::vector<float> standardDeviation() const; + + /** + @brief Compute the global min/max of all data phrases along the time axis + @return vector of min/max pairs across all phrases (along time axis, + full-size) + */ + std::vector<std::pair<float, float>> minmax() const; + + /** + @brief rescale a phrase given an offset and gain + @param offset constant offset to be subtracted + @param gain gain to be applied + */ + void rescale(std::vector<float> offset, std::vector<float> gain); + + /** + @brief normalize the training set by rescaling all phrases to the mean/std + of the whole training set + */ + void normalize(); + + ///@} + + /** + @brief total dimension of the training data + */ + Attribute<unsigned int> dimension; + + /** + @brief dimension of the input modality in bimodal mode + */ + Attribute<unsigned int> dimension_input; + + /** + @brief labels of the columns of the training set (e.g. descriptor names) + */ + Attribute<std::vector<std::string>> column_names; + + protected: + /** + @brief Monitors the training of each Model of the group. + */ + void onPhraseEvent(PhraseEvent const& e); + + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); + + /** + @brief create all the sub-training sets: one for each label + @details each subset contains only the phrase for the given label + */ + virtual void update(); + + /** + @brief defines if the phrase has its own memory + */ + bool own_memory_; + + /** + @brief defines if the phrase is bimodal + */ + bool bimodal_; + + /** + @brief Set containing all the labels present in the training set + */ + std::set<std::string> labels_; + + /** + @brief Training Phrases + @details Phrases are stored in a map: allows the easy addition/deletion of + phrases by index. + */ + std::map<int, std::shared_ptr<Phrase>> phrases_; + + /** + @brief Sub-ensembles of the training set for specific classes + */ + std::map<std::string, TrainingSet> sub_training_sets_; +}; +} + +#endif \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmm.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67c69dc5968dfeacb812b185a622bae2942656ea --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmm.cpp @@ -0,0 +1,271 @@ +/* + * xmmGmm.hpp + * + * Gaussian Mixture Model for Continuous Recognition and Regression + * (Multi-class) + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmGmm.hpp" +#include "../kmeans/xmmKMeans.hpp" + +xmm::GMM::GMM(bool bimodal) : Model<SingleClassGMM, GMM>(bimodal) {} + +xmm::GMM::GMM(GMM const& src) + : Model<SingleClassGMM, GMM>(src), results(src.results) {} + +xmm::GMM::GMM(Json::Value const& root) : Model<SingleClassGMM, GMM>(root) {} + +xmm::GMM& xmm::GMM::operator=(GMM const& src) { + if (this != &src) { + Model<SingleClassGMM, GMM>::operator=(src); + results = src.results; + } + return *this; +} + +void xmm::GMM::updateResults() { + double maxLogLikelihood = 0.0; + double normconst_instant(0.0); + double normconst_smoothed(0.0); + int i(0); + for (auto it = this->models.begin(); it != this->models.end(); ++it, ++i) { + results.instant_likelihoods[i] = it->second.results.instant_likelihood; + results.smoothed_log_likelihoods[i] = it->second.results.log_likelihood; + results.smoothed_likelihoods[i] = + exp(results.smoothed_log_likelihoods[i]); + + results.instant_normalized_likelihoods[i] = + results.instant_likelihoods[i]; + results.smoothed_normalized_likelihoods[i] = + results.smoothed_likelihoods[i]; + + normconst_instant += results.instant_normalized_likelihoods[i]; + normconst_smoothed += results.smoothed_normalized_likelihoods[i]; + + if (i == 0 || results.smoothed_log_likelihoods[i] > maxLogLikelihood) { + maxLogLikelihood = results.smoothed_log_likelihoods[i]; + results.likeliest = it->first; + } + } + + i = 0; + for (auto it = this->models.begin(); it != this->models.end(); ++it, ++i) { + results.instant_normalized_likelihoods[i] /= normconst_instant; + results.smoothed_normalized_likelihoods[i] /= normconst_smoothed; + } +} + +#pragma mark - +#pragma mark Performance +void xmm::GMM::reset() { + results.instant_likelihoods.resize(size()); + results.instant_normalized_likelihoods.resize(size()); + results.smoothed_likelihoods.resize(size()); + results.smoothed_normalized_likelihoods.resize(size()); + results.smoothed_log_likelihoods.resize(size()); + if (shared_parameters->bimodal.get()) { + unsigned int dimension_output = shared_parameters->dimension.get() - + shared_parameters->dimension_input.get(); + results.output_values.resize(dimension_output); + results.output_covariance.assign( + (configuration.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) + ? dimension_output * dimension_output + : dimension_output, + 0.0); + } + for (auto& model : models) { + model.second.reset(); + } +} + +void xmm::GMM::filter(std::vector<float> const& observation) { + checkTraining(); + int i(0); + for (auto& model : models) { + results.instant_likelihoods[i] = model.second.filter(observation); + i++; + } + + updateResults(); + + if (shared_parameters->bimodal.get()) { + unsigned int dimension = shared_parameters->dimension.get(); + unsigned int dimension_input = shared_parameters->dimension_input.get(); + unsigned int dimension_output = dimension - dimension_input; + + if (configuration.multiClass_regression_estimator == + MultiClassRegressionEstimator::Likeliest) { + results.output_values = + models[results.likeliest].results.output_values; + results.output_covariance = + models[results.likeliest].results.output_covariance; + + } else { + results.output_values.assign(dimension_output, 0.0); + results.output_covariance.assign( + (configuration.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) + ? dimension_output * dimension_output + : dimension_output, + 0.0); + + int i(0); + for (auto& model : models) { + for (int d = 0; d < dimension_output; d++) { + results.output_values[d] += + results.smoothed_normalized_likelihoods[i] * + model.second.results.output_values[d]; + if ((configuration.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full)) { + for (int d2 = 0; d2 < dimension_output; d2++) + results + .output_covariance[d * dimension_output + d2] += + results.smoothed_normalized_likelihoods[i] * + model.second.results + .output_covariance[d * dimension_output + + d2]; + } else { + results.output_covariance[d] += + results.smoothed_normalized_likelihoods[i] * + model.second.results.output_covariance[d]; + } + } + i++; + } + } + } +} + +//#pragma mark > Conversion & Extraction +// void xmm::GMM::makeBimodal(unsigned int dimension_input) +//{ +// check_training(); +// if (bimodal_) +// throw std::runtime_error("The model is already bimodal"); +// if (dimension_input >= dimension()) +// throw std::out_of_range("Request input dimension exceeds the current +// dimension"); +// +// try { +// this->referenceModel_.makeBimodal(dimension_input); +// } catch (std::exception const& e) { +// } +// bimodal_ = true; +// for (model_iterator it=this->models.begin(); it != this->models.end(); +// ++it) { +// it->second.makeBimodal(dimension_input); +// } +// set_trainingSet(NULL); +// results_predicted_output.resize(dimension() - this->dimension_input()); +// results_output_variance.resize(dimension() - this->dimension_input()); +//} +// +// void xmm::GMM::makeUnimodal() +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model is already unimodal"); +// this->referenceModel_.makeUnimodal(); +// for (model_iterator it=this->models.begin(); it != this->models.end(); +// ++it) { +// it->second.makeUnimodal(); +// } +// set_trainingSet(NULL); +// results_predicted_output.clear(); +// results_output_variance.clear(); +// bimodal_ = false; +//} +// +// xmm::GMM xmm::GMM::extractSubmodel(std::vector<unsigned int>& columns) const +//{ +// check_training(); +// if (columns.size() > this->dimension()) +// throw std::out_of_range("requested number of columns exceeds the +// dimension of the current model"); +// for (unsigned int column=0; column<columns.size(); ++column) { +// if (columns[column] >= this->dimension()) +// throw std::out_of_range("Some column indices exceeds the dimension +// of the current model"); +// } +// GMM target_model(*this); +// target_model.set_trainingSet(NULL); +// target_model.bimodal_ = false; +// target_model.referenceModel_ = +// this->referenceModel_.extractSubmodel(columns); +// for (model_iterator it=target_model.models.begin(); it != +// target_model.models.end(); ++it) { +// it->second = this->models.at(it->first).extractSubmodel(columns); +// } +// target_model.results_predicted_output.clear(); +// target_model.results_output_variance.clear(); +// return target_model; +//} +// +// xmm::GMM xmm::GMM::extractSubmodel_input() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_input(dimension_input()); +// for (unsigned int i=0; i<dimension_input(); ++i) { +// columns_input[i] = i; +// } +// return extractSubmodel(columns_input); +//} +// +// xmm::GMM xmm::GMM::extractSubmodel_output() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_output(dimension() - dimension_input()); +// for (unsigned int i=dimension_input(); i<dimension(); ++i) { +// columns_output[i-dimension_input()] = i; +// } +// return extractSubmodel(columns_output); +//} +// +// xmm::GMM xmm::GMM::extract_inverse_model() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns(dimension()); +// for (unsigned int i=0; i<dimension()-dimension_input(); ++i) { +// columns[i] = i+dimension_input(); +// } +// for (unsigned int i=dimension()-dimension_input(), j=0; i<dimension(); ++i, +// ++j) { +// columns[i] = j; +// } +// GMM target_model = extractSubmodel(columns); +// target_model.makeBimodal(dimension()-dimension_input()); +// return target_model; +//} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmm.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..03d92472361925c63c361636479d017eb988e67d --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmm.hpp @@ -0,0 +1,158 @@ +/* + * xmmGmm.hpp + * + * Gaussian Mixture Model for Continuous Recognition and Regression + * (Multi-class) + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmGmm_h +#define xmmGmm_h + +#include "../../core/distributions/xmmGaussianDistribution.hpp" +#include "../../core/model/xmmModel.hpp" +#include "xmmGmmSingleClass.hpp" + +namespace xmm { +/** + @ingroup GMM + @brief Gaussian Mixture Model for Continuous Recognition and Regression + (Multi-class) + */ +class GMM : public Model<SingleClassGMM, GMM> { + public: + /** + @brief Constructor + @param bimodal specifies if the model should be used for regression + */ + GMM(bool bimodal = false); + + /** + @brief Copy Constructor + @param src Source Model + */ + GMM(GMM const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit GMM(Json::Value const& root); + + /** + @brief Assignment + @param src Source Model + */ + GMM& operator=(GMM const& src); + + /** @name Performance */ + ///@{ + + /** + @brief Resets the fitering process (recognition or regression) + */ + virtual void reset(); + + /** + @brief filters a incoming observation (performs recognition or regression) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + */ + virtual void filter(std::vector<float> const& observation); + + ///@} + + // + // /** + // @brief Convert to bimodal GMM in place + // @param dimension_input dimension of the input modality + // @throws runtime_error if the model is already bimodal + // @throws out_of_range if the requested input dimension is too + // large + // */ + // void makeBimodal(unsigned int dimension_input); + // + // /** + // @brief Convert to unimodal GMM in place + // @throws runtime_error if the model is already unimodal + // */ + // void makeUnimodal(); + // + // /** + // @brief extract a submodel with the given columns + // @param columns columns indices in the target order + // @throws runtime_error if the model is training + // @throws out_of_range if the number or indices of the requested + // columns exceeds the current dimension + // @return a GMM from the current model considering only the target + // columns + // */ + // GMM extractSubmodel(std::vector<unsigned int>& columns) const; + // + // /** + // @brief extract the submodel of the input modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal GMM of the input modality from the current + // bimodal model + // */ + // GMM extractSubmodel_input() const; + // + // /** + // @brief extract the submodel of the output modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal GMM of the output modality from the current + // bimodal model + // */ + // GMM extractSubmodel_output() const; + // + // /** + // @brief extract the model with reversed input and output + // modalities + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a bimodal GMM that swaps the input and output modalities + // */ + // GMM extract_inverse_model() const; + + /** + @brief Results of the Filtering Process (Recognition + Regression) + */ + Results<GMM> results; + + protected: + /** + @brief Update the results (Likelihoods) + */ + virtual void updateResults(); +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmParameters.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmParameters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e4fdb7f91eb3a961eeb4c3440b1c039b30ae76c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmParameters.cpp @@ -0,0 +1,132 @@ +/* + * xmmGmmParameters.cpp + * + * Parameters of Gaussian Mixture Models + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmGmmParameters.hpp" + +xmm::ClassParameters<xmm::GMM>::ClassParameters() + : changed(true), + gaussians(10, 1), + relative_regularization(1.0e-2, 1e-20), + absolute_regularization(1.0e-3, 1e-20), + covariance_mode(GaussianDistribution::CovarianceMode::Full) { + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); +} + +xmm::ClassParameters<xmm::GMM>::ClassParameters(ClassParameters<GMM> const& src) + : changed(true), + gaussians(src.gaussians), + relative_regularization(src.relative_regularization), + absolute_regularization(src.absolute_regularization), + covariance_mode(src.covariance_mode) { + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); +} + +xmm::ClassParameters<xmm::GMM>::ClassParameters(Json::Value const& root) + : changed(true), + gaussians(10, 1), + relative_regularization(1.0e-2, 1e-20), + absolute_regularization(1.0e-3, 1e-20), + covariance_mode(GaussianDistribution::CovarianceMode::Full) { + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + + gaussians.set(root["gaussians"].asInt()); + relative_regularization.set(root["relative_regularization"].asFloat()); + absolute_regularization.set(root["absolute_regularization"].asFloat()); + covariance_mode.set(static_cast<GaussianDistribution::CovarianceMode>( + root["covariance_mode"].asInt())); +} + +xmm::ClassParameters<xmm::GMM>& xmm::ClassParameters<xmm::GMM>::operator=( + ClassParameters<GMM> const& src) { + if (this != &src) { + changed = true; + gaussians = src.gaussians; + relative_regularization = src.relative_regularization; + absolute_regularization = src.absolute_regularization; + covariance_mode = src.covariance_mode; + + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::GMM>::onAttributeChange); + } + return *this; +} + +Json::Value xmm::ClassParameters<xmm::GMM>::toJson() const { + Json::Value root; + root["gaussians"] = static_cast<int>(gaussians.get()); + root["relative_regularization"] = relative_regularization.get(); + root["absolute_regularization"] = absolute_regularization.get(); + root["covariance_mode"] = static_cast<int>(covariance_mode.get()); + return root; +} + +void xmm::ClassParameters<xmm::GMM>::fromJson(Json::Value const& root) { + try { + ClassParameters<GMM> tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +void xmm::ClassParameters<xmm::GMM>::onAttributeChange( + AttributeBase* attr_pointer) { + changed = true; + attr_pointer->changed = false; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmParameters.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmParameters.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bafd8c54b5054dd205aaf038a8aab29d0eebcc9a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmParameters.hpp @@ -0,0 +1,132 @@ +/* + * xmmGmmParameters.hpp + * + * Parameters of Gaussian Mixture Models + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmGMMParameters_hpp +#define xmmGMMParameters_hpp + +#include "../../core/distributions/xmmGaussianDistribution.hpp" +#include "../../core/model/xmmModelParameters.hpp" + +namespace xmm { +/** + @defgroup GMM [Models] Gaussian Mixture Models + */ + +/** + Dummy structure for template specialization + */ +class GMM; + +/** + @ingroup GMM + @brief Parameters specific to each class of a Gaussian Mixture Model + */ +template <> +class ClassParameters<GMM> : public Writable { + public: + /** + @brief Default Constructor + */ + ClassParameters(); + + /** + @brief Copy Constructor + @param src Source Object + */ + ClassParameters(ClassParameters<GMM> const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit ClassParameters(Json::Value const& root); + + /** + @brief Assignment + @param src Source Object + */ + ClassParameters& operator=(ClassParameters<GMM> const& src); + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root); + + ///@} + + /** + @brief specifies if parameters have changed (model is invalid) + */ + bool changed = false; + + /** + @brief Number of Gaussian Mixture Components + */ + Attribute<unsigned int> gaussians; + + /** + @brief Offset Added to the diagonal of covariance matrices for convergence + (Relative to Data Variance) + */ + Attribute<double> relative_regularization; + + /** + @brief Offset Added to the diagonal of covariance matrices for convergence + (minimum value) + */ + Attribute<double> absolute_regularization; + + /** + @brief Covariance Mode + */ + Attribute<GaussianDistribution::CovarianceMode> covariance_mode; + + protected: + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmSingleClass.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmSingleClass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64d7bd3b28df001844231f7f62cb733b064f996a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmSingleClass.cpp @@ -0,0 +1,641 @@ +/* + * xmmGmmSingleClass.cpp + * + * Gaussian Mixture Model Definition for a Single Class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "../kmeans/xmmKMeans.hpp" +#include "xmmGmmSingleClass.hpp" +#include <algorithm> + +xmm::SingleClassGMM::SingleClassGMM(std::shared_ptr<SharedParameters> p) + : SingleClassProbabilisticModel(p) {} + +xmm::SingleClassGMM::SingleClassGMM(SingleClassGMM const& src) + : SingleClassProbabilisticModel(src), + parameters(src.parameters), + components(src.components), + mixture_coeffs(src.mixture_coeffs) { + beta.resize(parameters.gaussians.get()); +} + +xmm::SingleClassGMM::SingleClassGMM(std::shared_ptr<SharedParameters> p, + Json::Value const& root) + : SingleClassProbabilisticModel(p, root) { + parameters.fromJson(root["parameters"]); + + allocate(); + + json2vector(root["mixture_coeffs"], mixture_coeffs, + parameters.gaussians.get()); + + int c(0); + for (auto p : root["components"]) { + components[c++].fromJson(p); + } + + updateInverseCovariances(); +} + +xmm::SingleClassGMM& xmm::SingleClassGMM::operator=(SingleClassGMM const& src) { + if (this != &src) { + SingleClassProbabilisticModel::operator=(src); + parameters = src.parameters; + beta.resize(parameters.gaussians.get()); + mixture_coeffs = src.mixture_coeffs; + components = src.components; + } + return *this; +}; + +void xmm::SingleClassGMM::reset() { SingleClassProbabilisticModel::reset(); } + +double xmm::SingleClassGMM::filter(std::vector<float> const& observation) { + check_training(); + double instantaneous_likelihood = likelihood(observation); + if (shared_parameters->bimodal.get()) { + regression(observation); + } + return instantaneous_likelihood; +} + +void xmm::SingleClassGMM::emAlgorithmInit(TrainingSet* trainingSet) { + initParametersToDefault(trainingSet->standardDeviation()); + initMeansWithKMeans(trainingSet); + initCovariances_fullyObserved(trainingSet); + addCovarianceOffset(); + updateInverseCovariances(); +} + +Json::Value xmm::SingleClassGMM::toJson() const { + check_training(); + Json::Value root = SingleClassProbabilisticModel::toJson(); + root["mixture_coeffs"] = vector2json(mixture_coeffs); + root["parameters"] = parameters.toJson(); + root["components"].resize( + static_cast<Json::ArrayIndex>(parameters.gaussians.get())); + for (int c = 0; c < parameters.gaussians.get(); c++) { + root["components"][c] = components[c].toJson(); + } + return root; +} + +void xmm::SingleClassGMM::fromJson(Json::Value const& root) { + check_training(); + try { + SingleClassGMM tmp(shared_parameters, root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +// void xmm::SingleClassGMM::makeBimodal(unsigned int dimension_input) +//{ +// check_training(); +// if (bimodal_) +// throw std::runtime_error("The model is already bimodal"); +// if (dimension_input >= dimension_) +// throw std::out_of_range("Request input dimension exceeds the current +// dimension"); +// flags_ = BIMODAL; +// bimodal_ = true; +// dimension_input_ = dimension_input; +// for (mixture_iterator component = components.begin() ; component != +// components.end(); ++component) { +// component->makeBimodal(dimension_input); +// } +// baseResults_predicted_output.resize(dimension_ - dimension_input_); +// results.output_variance.resize(dimension_ - dimension_input_); +//} +// +// void xmm::SingleClassGMM::makeUnimodal() +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model is already unimodal"); +// flags_ = NONE; +// bimodal_ = false; +// dimension_input_ = 0; +// for (mixture_iterator component = components.begin() ; component != +// components.end(); ++component) { +// component->makeUnimodal(); +// } +// baseResults_predicted_output.clear(); +// results.output_variance.clear(); +//} +// +// xmm::SingleClassGMM +// xmm::SingleClassGMM::extractSubmodel(std::vector<unsigned int>& columns) const +//{ +// check_training(); +// if (columns.size() > dimension_) +// throw std::out_of_range("requested number of columns exceeds the +// dimension of the current model"); +// for (unsigned int column=0; column<columns.size(); ++column) { +// if (columns[column] >= dimension_) +// throw std::out_of_range("Some column indices exceeds the dimension +// of the current model"); +// } +// unsigned int new_dim =columns.size(); +// GMM target_model(*this); +// target_model.setTrainingCallback(NULL, NULL); +// target_model.bimodal_ = false; +// target_model.dimension_ = static_cast<unsigned int>(new_dim); +// target_model.dimension_input_ = 0; +// target_model.flags_ = NONE; +// target_model.allocate(); +// for (unsigned int c=0; c<nbMixtureComponents_; ++c) { +// target_model.components[c] = components[c].extractSubmodel(columns); +// } +// target_model.baseResults_predicted_output.clear(); +// target_model.results.output_variance.clear(); +// return target_model; +//} +// +// xmm::SingleClassGMM xmm::SingleClassGMM::extractSubmodel_input() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_input(dimension_input_); +// for (unsigned int i=0; i<dimension_input_; ++i) { +// columns_input[i] = i; +// } +// return extractSubmodel(columns_input); +//} +// +// xmm::SingleClassGMM xmm::SingleClassGMM::extractSubmodel_output() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_output(dimension_ - dimension_input_); +// for (unsigned int i=dimension_input_; i<dimension_; ++i) { +// columns_output[i-dimension_input_] = i; +// } +// return extractSubmodel(columns_output); +//} +// +// xmm::SingleClassGMM xmm::SingleClassGMM::extract_inverse_model() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns(dimension_); +// for (unsigned int i=0; i<dimension_-dimension_input_; ++i) { +// columns[i] = i+dimension_input_; +// } +// for (unsigned int i=dimension_-dimension_input_, j=0; i<dimension_; ++i, +// ++j) { +// columns[i] = j; +// } +// GMM target_model = extractSubmodel(columns); +// target_model.makeBimodal(dimension_-dimension_input_); +// return target_model; +//} + +void xmm::SingleClassGMM::allocate() { + mixture_coeffs.resize(parameters.gaussians.get()); + beta.resize(parameters.gaussians.get()); + components.assign( + parameters.gaussians.get(), + GaussianDistribution(shared_parameters->bimodal.get(), + shared_parameters->dimension.get(), + shared_parameters->dimension_input.get(), + parameters.covariance_mode.get())); +} + +double xmm::SingleClassGMM::obsProb(const float* observation, + int mixtureComponent) const { + double p(0.); + + if (mixtureComponent < 0) { + for (mixtureComponent = 0; + mixtureComponent < parameters.gaussians.get(); + mixtureComponent++) { + p += obsProb(observation, mixtureComponent); + } + } else { + if (mixtureComponent >= parameters.gaussians.get()) + throw std::out_of_range( + "The index of the Gaussian Mixture Component is out of bounds"); + p = mixture_coeffs[mixtureComponent] * + components[mixtureComponent].likelihood(observation); + } + + return p; +} + +double xmm::SingleClassGMM::obsProb_input(const float* observation_input, + int mixtureComponent) const { + if (!shared_parameters->bimodal.get()) + throw std::runtime_error( + "Model is not bimodal. Use the function 'obsProb'"); + double p(0.); + + if (mixtureComponent < 0) { + for (mixtureComponent = 0; + mixtureComponent < parameters.gaussians.get(); + mixtureComponent++) { + p += obsProb_input(observation_input, mixtureComponent); + } + } else { + p = mixture_coeffs[mixtureComponent] * + components[mixtureComponent].likelihood_input(observation_input); + } + + return p; +} + +double xmm::SingleClassGMM::obsProb_bimodal(const float* observation_input, + const float* observation_output, + int mixtureComponent) const { + if (!shared_parameters->bimodal.get()) + throw std::runtime_error( + "Model is not bimodal. Use the function 'obsProb'"); + double p(0.); + + if (mixtureComponent < 0) { + for (mixtureComponent = 0; + mixtureComponent < parameters.gaussians.get(); + mixtureComponent++) { + p += obsProb_bimodal(observation_input, observation_output, + mixtureComponent); + } + } else { + p = mixture_coeffs[mixtureComponent] * + components[mixtureComponent].likelihood_bimodal(observation_input, + observation_output); + } + + return p; +} + +void xmm::SingleClassGMM::initMeansWithKMeans(TrainingSet* trainingSet) { + if (!trainingSet || trainingSet->empty()) return; + int dimension = static_cast<int>(shared_parameters->dimension.get()); + + KMeans kmeans(parameters.gaussians.get()); + kmeans.initialization_mode = KMeans::InitializationMode::Biased; + kmeans.train(trainingSet); + for (int c = 0; c < parameters.gaussians.get(); c++) { + for (unsigned int d = 0; d < dimension; ++d) { + components[c].mean[d] = kmeans.centers[c * dimension + d]; + } + } +} + +void xmm::SingleClassGMM::initCovariances_fullyObserved( + TrainingSet* trainingSet) { + // TODO: simplify with covariance symmetricity + // TODO: If Kmeans, covariances from cluster members + if (!trainingSet || trainingSet->empty()) return; + int dimension = static_cast<int>(shared_parameters->dimension.get()); + + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int n = 0; n < parameters.gaussians.get(); n++) + components[n].covariance.assign(dimension * dimension, 0.0); + } else { + for (int n = 0; n < parameters.gaussians.get(); n++) + components[n].covariance.assign(dimension, 0.0); + } + + std::vector<double> gmeans(parameters.gaussians.get() * dimension, 0.0); + std::vector<int> factor(parameters.gaussians.get(), 0); + for (auto phrase_it = trainingSet->begin(); phrase_it != trainingSet->end(); + phrase_it++) { + unsigned int step = + phrase_it->second->size() / parameters.gaussians.get(); + unsigned int offset(0); + for (int n = 0; n < parameters.gaussians.get(); n++) { + for (int t = 0; t < step; t++) { + for (int d1 = 0; d1 < dimension; d1++) { + gmeans[n * dimension + d1] += + phrase_it->second->getValue(offset + t, d1); + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension; d2++) { + components[n].covariance[d1 * dimension + d2] += + phrase_it->second->getValue(offset + t, d1) * + phrase_it->second->getValue(offset + t, d2); + } + } else { + float value = + phrase_it->second->getValue(offset + t, d1); + components[n].covariance[d1] += value * value; + } + } + } + offset += step; + factor[n] += step; + } + } + + for (int n = 0; n < parameters.gaussians.get(); n++) { + for (int d1 = 0; d1 < dimension; d1++) { + gmeans[n * dimension + d1] /= factor[n]; + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension; d2++) + components[n].covariance[d1 * dimension + d2] /= factor[n]; + } else { + components[n].covariance[d1] /= factor[n]; + } + } + } + + for (int n = 0; n < parameters.gaussians.get(); n++) { + for (int d1 = 0; d1 < dimension; d1++) { + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension; d2++) + components[n].covariance[d1 * dimension + d2] -= + gmeans[n * dimension + d1] * gmeans[n * dimension + d2]; + } else { + components[n].covariance[d1] -= + gmeans[n * dimension + d1] * gmeans[n * dimension + d1]; + } + } + } +} + +double xmm::SingleClassGMM::emAlgorithmUpdate(TrainingSet* trainingSet) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + double log_prob(0.); + + int totalLength(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); ++it) + totalLength += it->second->size(); + + std::vector<std::vector<double> > p(parameters.gaussians.get()); + std::vector<double> E(parameters.gaussians.get(), 0.0); + for (int c = 0; c < parameters.gaussians.get(); c++) { + p[c].resize(totalLength); + E[c] = 0.; + } + + int tbase(0); + + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); ++it) { + unsigned int T = it->second->size(); + for (int t = 0; t < T; t++) { + double norm_const(0.); + for (int c = 0; c < parameters.gaussians.get(); c++) { + if (shared_parameters->bimodal.get()) { + p[c][tbase + t] = + obsProb_bimodal(it->second->getPointer_input(t), + it->second->getPointer_output(t), c); + } else { + p[c][tbase + t] = obsProb(it->second->getPointer(t), c); + } + + if (p[c][tbase + t] == 0. || std::isnan(p[c][tbase + t]) || + std::isinf(p[c][tbase + t])) { + p[c][tbase + t] = 1e-100; + } + norm_const += p[c][tbase + t]; + } + for (int c = 0; c < parameters.gaussians.get(); c++) { + p[c][tbase + t] /= norm_const; + E[c] += p[c][tbase + t]; + } + log_prob += log(norm_const); + } + tbase += T; + } + + // Estimate Mixture coefficients + for (int c = 0; c < parameters.gaussians.get(); c++) { + mixture_coeffs[c] = E[c] / double(totalLength); + } + + // Estimate means + for (int c = 0; c < parameters.gaussians.get(); c++) { + for (int d = 0; d < dimension; d++) { + components[c].mean[d] = 0.; + tbase = 0; + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); + ++it) { + unsigned int T = it->second->size(); + for (int t = 0; t < T; t++) { + components[c].mean[d] += + p[c][tbase + t] * it->second->getValue(t, d); + } + tbase += T; + } + components[c].mean[d] /= E[c]; + } + } + + // estimate covariances + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int c = 0; c < parameters.gaussians.get(); c++) { + for (int d1 = 0; d1 < dimension; d1++) { + for (int d2 = d1; d2 < dimension; d2++) { + components[c].covariance[d1 * dimension + d2] = 0.; + tbase = 0; + for (auto it = trainingSet->cbegin(); + it != trainingSet->cend(); ++it) { + unsigned int T = it->second->size(); + for (int t = 0; t < T; t++) { + components[c].covariance[d1 * dimension + d2] += + p[c][tbase + t] * (it->second->getValue(t, d1) - + components[c].mean[d1]) * + (it->second->getValue(t, d2) - + components[c].mean[d2]); + } + tbase += T; + } + components[c].covariance[d1 * dimension + d2] /= E[c]; + if (d1 != d2) + components[c].covariance[d2 * dimension + d1] = + components[c].covariance[d1 * dimension + d2]; + } + } + } + } else { + for (int c = 0; c < parameters.gaussians.get(); c++) { + for (int d1 = 0; d1 < dimension; d1++) { + components[c].covariance[d1] = 0.; + tbase = 0; + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); + ++it) { + unsigned int T = it->second->size(); + for (int t = 0; t < T; t++) { + float value = (it->second->getValue(t, d1) - + components[c].mean[d1]); + components[c].covariance[d1] += + p[c][tbase + t] * value * value; + } + tbase += T; + } + components[c].covariance[d1] /= E[c]; + } + } + } + + addCovarianceOffset(); + updateInverseCovariances(); + + return log_prob; +} + +void xmm::SingleClassGMM::initParametersToDefault( + std::vector<float> const& dataStddev) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + + double norm_coeffs(0.); + current_regularization.resize(dataStddev.size()); + for (int i = 0; i < dataStddev.size(); i++) { + current_regularization[i] = + std::max(parameters.absolute_regularization.get(), + parameters.relative_regularization.get() * dataStddev[i]); + } + for (int c = 0; c < parameters.gaussians.get(); c++) { + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + components[c].covariance.assign( + dimension * dimension, + parameters.absolute_regularization.get() / 2.); + } else { + components[c].covariance.assign(dimension, 0.); + } + components[c].regularize(current_regularization); + mixture_coeffs[c] = 1. / float(parameters.gaussians.get()); + norm_coeffs += mixture_coeffs[c]; + } + for (int c = 0; c < parameters.gaussians.get(); c++) { + mixture_coeffs[c] /= norm_coeffs; + } +} + +void xmm::SingleClassGMM::normalizeMixtureCoeffs() { + double norm_const(0.); + for (int c = 0; c < parameters.gaussians.get(); c++) { + norm_const += mixture_coeffs[c]; + } + if (norm_const > 0) { + for (int c = 0; c < parameters.gaussians.get(); c++) { + mixture_coeffs[c] /= norm_const; + } + } else { + for (int c = 0; c < parameters.gaussians.get(); c++) { + mixture_coeffs[c] = 1 / float(parameters.gaussians.get()); + } + } +} + +void xmm::SingleClassGMM::addCovarianceOffset() { + for (auto& component : components) { + component.regularize(current_regularization); + } +} + +void xmm::SingleClassGMM::updateInverseCovariances() { + try { + for (auto& component : components) { + component.updateInverseCovariance(); + } + } catch (std::exception& e) { + throw std::runtime_error( + "Matrix inversion error: varianceoffset must be too small"); + } +} + +void xmm::SingleClassGMM::regression( + std::vector<float> const& observation_input) { + check_training(); + unsigned int dimension_output = shared_parameters->dimension.get() - + shared_parameters->dimension_input.get(); + results.output_values.assign(dimension_output, 0.0); + results.output_covariance.assign( + (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) + ? dimension_output * dimension_output + : dimension_output, + 0.0); + std::vector<float> tmp_output_values(dimension_output, 0.0); + + for (int c = 0; c < parameters.gaussians.get(); c++) { + components[c].regression(observation_input, tmp_output_values); + for (int d = 0; d < dimension_output; ++d) { + results.output_values[d] += beta[c] * tmp_output_values[d]; + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension_output; ++d2) + results.output_covariance[d * dimension_output + d2] += + beta[c] * beta[c] * + components[c] + .output_covariance[d * dimension_output + d2]; + } else { + results.output_covariance[d] += + beta[c] * beta[c] * components[c].output_covariance[d]; + } + } + } +} + +double xmm::SingleClassGMM::likelihood( + std::vector<float> const& observation, + std::vector<float> const& observation_output) { + check_training(); + double likelihood(0.); + for (int c = 0; c < parameters.gaussians.get(); c++) { + if (shared_parameters->bimodal.get()) { + if (observation_output.empty()) + beta[c] = obsProb_input(&observation[0], c); + else + beta[c] = + obsProb_bimodal(&observation[0], &observation_output[0], c); + } else { + beta[c] = obsProb(&observation[0], c); + } + likelihood += beta[c]; + } + for (int c = 0; c < parameters.gaussians.get(); c++) { + beta[c] /= likelihood; + } + + results.instant_likelihood = likelihood; + updateResults(); + return likelihood; +} + +void xmm::SingleClassGMM::updateResults() { + likelihood_buffer_.push(log(results.instant_likelihood)); + results.log_likelihood = 0.0; + unsigned int bufSize = likelihood_buffer_.size_t(); + for (unsigned int i = 0; i < bufSize; i++) { + results.log_likelihood += likelihood_buffer_(0, i); + } + results.log_likelihood /= double(bufSize); +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmSingleClass.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmSingleClass.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2543de0069055894ca2e53da65b665ef5bb01ff5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/gmm/xmmGmmSingleClass.hpp @@ -0,0 +1,343 @@ +/* + * xmmGmmSingleClass.hpp + * + * Gaussian Mixture Model Definition for a Single Class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmGmmSingleClass_hpp +#define xmmGmmSingleClass_hpp + +#include "../../core/model/xmmModelResults.hpp" +#include "../../core/model/xmmModelSingleClass.hpp" +#include "xmmGmmParameters.hpp" +#include <memory> + +namespace xmm { +const std::vector<float> null_vector_float; + +/** + @ingroup GMM + @brief Single-Class Gaussian Mixture Model + @details Multivariate Gaussian Mixture Model. Supports Bimodal data and + Gaussian Mixture Regression. + Can be either autonomous or a state of a HMM: defines observation probabilities + for each state. + */ +class SingleClassGMM : public SingleClassProbabilisticModel { + public: + template <typename SingleClassModel, typename ModelType> + friend class Model; + friend class SingleClassHMM; + friend class HierarchicalHMM; + + /** + @brief Constructor + @param p pointer to a shared parameters object (owned by a Model) + */ + SingleClassGMM(std::shared_ptr<SharedParameters> p = NULL); + + /** + @brief Copy constructor + @param src Source GMM + */ + SingleClassGMM(SingleClassGMM const& src); + + /** + @brief Copy constructor + @param p pointer to a shared parameters object (owned by a Model) + @param root Json structure + */ + explicit SingleClassGMM(std::shared_ptr<SharedParameters> p, + Json::Value const& root); + + /** + @brief Assignment + @param src Source GMM + */ + SingleClassGMM& operator=(SingleClassGMM const& src); + + /** @name Performance */ + ///@{ + + /** + @brief Resets the fitering process (recognition or regression) + */ + void reset(); + + /** + @brief filters a incoming observation (performs recognition or regression) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + @return likelihood of the observation + */ + double filter(std::vector<float> const& observation); + + ///@} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + void fromJson(Json::Value const& root); + + ///@} + + // + // /** + // @brief Convert to bimodal GMM in place + // @param dimension_input dimension of the input modality + // @throws runtime_error if the model is already bimodal + // @throws out_of_range if the requested input dimension is too + // large + // */ + // void makeBimodal(unsigned int dimension_input); + // + // /** + // @brief Convert to unimodal GMM in place + // @throws runtime_error if the model is already unimodal + // */ + // void makeUnimodal(); + // + // /** + // @brief extract a submodel with the given columns + // @param columns columns indices in the target order + // @throws runtime_error if the model is training + // @throws out_of_range if the number or indices of the requested + // columns exceeds the current dimension + // @return a GMM from the current model considering only the target + // columns + // */ + // GMM extractSubmodel(std::vector<unsigned int>& columns) const; + // + // /** + // @brief extract the submodel of the input modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal GMM of the input modality from the current + // bimodal model + // */ + // GMM extractSubmodel_input() const; + // + // /** + // @brief extract the submodel of the output modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal GMM of the output modality from the current + // bimodal model + // */ + // GMM extractSubmodel_output() const; + // + // /** + // @brief extract the model with reversed input and output + // modalities + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a bimodal GMM that swaps the input and output modalities + // */ + // GMM extract_inverse_model() const; + + /** + @brief Model Parameters + */ + ClassParameters<GMM> parameters; + + /** + @brief Results of the filtering process (recognition & regression) + */ + ClassResults<GMM> results; + + /** + @brief Vector of Gaussian Components + */ + std::vector<GaussianDistribution> components; + + /** + @brief Mixture Coefficients + */ + std::vector<float> mixture_coeffs; + + /** + @brief Beta probabilities: likelihood of each component + */ + std::vector<double> beta; + + protected: + /** + @brief Allocate model parameters + */ + void allocate(); + + /** + @brief Observation probability + @param observation observation vector (must be of size 'dimension') + @param mixtureComponent index of the mixture component. if unspecified or + negative, + full mixture observation probability is computed + @return likelihood of the observation given the model + @throws out_of_range if the index of the Gaussian Mixture Component is out + of bounds + @throws runtime_error if the Covariance Matrix is not invertible + */ + double obsProb(const float* observation, int mixtureComponent = -1) const; + + /** + @brief Observation probability on the input modality + @param observation_input observation vector of the input modality (must be + of size 'dimension_input') + @param mixtureComponent index of the mixture component. if unspecified or + negative, + full mixture observation probability is computed + @return likelihood of the observation of the input modality given the model + @throws runtime_error if the model is not bimodal + @throws runtime_error if the Covariance Matrix of the input modality is not + invertible + */ + double obsProb_input(const float* observation_input, + int mixtureComponent = -1) const; + + /** + @brief Observation probability for bimodal mode + @param observation_input observation vector of the input modality (must be + of size 'dimension_input') + @param observation_output observation vector of the input output (must be + of size 'dimension - dimension_input') + @param mixtureComponent index of the mixture component. if unspecified or + negative, + full mixture observation probability is computed + @return likelihood of the observation of the input modality given the model + @throws runtime_error if the model is not bimodal + @throws runtime_error if the Covariance Matrix is not invertible + */ + double obsProb_bimodal(const float* observation_input, + const float* observation_output, + int mixtureComponent = -1) const; + + /** + @brief Initialize the EM Training Algorithm + @details Initializes the Gaussian Components from the first phrase + of the Training Set + */ + void emAlgorithmInit(TrainingSet* trainingSet); + + /** + @brief Update Function of the EM algorithm + @return likelihood of the data given the current parameters (E-step) + */ + double emAlgorithmUpdate(TrainingSet* trainingSet); + + /** + @brief Initialize model parameters to default values. + @details Mixture coefficients are then equiprobable + */ + void initParametersToDefault(std::vector<float> const& dataStddev); + + /** + @brief Initialize the means of the Gaussian components with a Biased + K-means + */ + void initMeansWithKMeans(TrainingSet* trainingSet); + + /** + @brief Initialize the Covariances of the Gaussian components using a fully + observed approximation + */ + void initCovariances_fullyObserved(TrainingSet* trainingSet); + + /** + @brief Normalize mixture coefficients + */ + void normalizeMixtureCoeffs(); + + /** + @brief Add offset to the diagonal of the covariance matrices + @details Guarantees convergence through covariance matrix invertibility + */ + void addCovarianceOffset(); + + /** + @brief Update inverse covariances of each Gaussian component + @throws runtime_error if one of the covariance matrices is not invertible + */ + void updateInverseCovariances(); + + /** + @brief Compute likelihood and estimate components probabilities + @details If the model is bimodal, the likelihood is computed only on the + input modality, + except if 'observation_output' is specified. + Updates the likelihood buffer used to smooth likelihoods. + @param observation observation vector (full size for unimodal, input + modality for bimodal) + @param observation_output observation vector of the output modality + */ + double likelihood( + std::vector<float> const& observation, + std::vector<float> const& observation_output = null_vector_float); + + /** + @brief Compute Gaussian Mixture Regression + @details Estimates the output modality using covariance-based regression + weighted by components' likelihood + @warning the function does not estimates the likelihoods, use 'likelihood' + before performing + the regression. + @param observation_input observation vector of the input modality + */ + void regression(std::vector<float> const& observation_input); + + /** + @brief update the content of the likelihood buffer and return average + likelihood. + @details The method also updates the cumulative log-likelihood computed + over a window (cumulativeloglikelihood) + */ + void updateResults(); + + /** + @brief vector containing the regularization values over each dimension + @details computed by combining relative and absolute regularization with + the + training set + */ + std::vector<double> current_regularization; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHierarchicalHmm.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHierarchicalHmm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4afd41a0c9020ec5f60d6f839ecbe58a690807b5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHierarchicalHmm.cpp @@ -0,0 +1,634 @@ +/* + * hierarchical_hmm.cpp + * + * Hierarchical Hidden Markov Model for continuous recognition and regression + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmHierarchicalHmm.hpp" +#include <algorithm> + +xmm::HierarchicalHMM::HierarchicalHMM(bool bimodal) + : Model<SingleClassHMM, HMM>(bimodal), forward_initialized_(false) {} + +xmm::HierarchicalHMM::HierarchicalHMM(HierarchicalHMM const &src) + : Model<SingleClassHMM, HMM>(src) { + results = src.results; + prior = src.prior; + exit_transition = src.exit_transition; + transition = src.transition; + frontier_v1_ = src.frontier_v1_; + frontier_v2_ = src.frontier_v2_; + forward_initialized_ = false; +} + +xmm::HierarchicalHMM::HierarchicalHMM(Json::Value const &root) + : Model<SingleClassHMM, HMM>(root), forward_initialized_(false) { + prior.resize(size()); + json2vector(root["prior"], prior, size()); + transition.resize(size()); + for (int i = 0; i < size(); i++) { + transition[i].resize(size()); + json2vector(root["transition"][i], transition[i], size()); + } + exit_transition.resize(size()); + json2vector(root["exit_transition"], exit_transition, size()); +} + +xmm::HierarchicalHMM &xmm::HierarchicalHMM::operator=( + HierarchicalHMM const &src) { + if (this != &src) { + Model<SingleClassHMM, HMM>::operator=(src); + results = src.results; + prior = src.prior; + exit_transition = src.exit_transition; + transition = src.transition; + frontier_v1_ = src.frontier_v1_; + frontier_v2_ = src.frontier_v2_; + forward_initialized_ = false; + } + return *this; +} + +void xmm::HierarchicalHMM::clear() { + Model<SingleClassHMM, HMM>::clear(); + prior.clear(); + transition.clear(); + exit_transition.clear(); +} + +void xmm::HierarchicalHMM::addExitPoint(int state, float proba) { + // prevent_attribute_change(); + for (auto &model : models) { + model.second.addExitPoint(state, proba); + } +} + +void xmm::HierarchicalHMM::normalizeTransitions() { + double sumPrior(0.0); + int num_models = static_cast<int>(size()); + for (int i = 0; i < num_models; i++) { + sumPrior += prior[i]; + double sumTrans(0.0); + for (int j = 0; j < num_models; j++) sumTrans += transition[i][j]; + if (sumTrans > 0.0) + for (int j = 0; j < num_models; j++) transition[i][j] /= sumTrans; + } + for (int i = 0; i < size(); i++) prior[i] /= sumPrior; +} + +void xmm::HierarchicalHMM::joinTraining() { + Model<SingleClassHMM, HMM>::joinTraining(); + updateTransitionParameters(); +} + +void xmm::HierarchicalHMM::updateTransitionParameters() { + if (this->size() == prior.size()) // number of primitives has not changed + return; + + updatePrior(); + updateTransition(); + + updateExitProbabilities(); // Update exit probabilities of Submodels + // (signal level) +} + +void xmm::HierarchicalHMM::updatePrior() { + prior.assign(size(), 1. / static_cast<double>(this->size())); +} + +void xmm::HierarchicalHMM::updateTransition() { + int num_classes = static_cast<int>(size()); + exit_transition.assign(num_classes, DEFAULT_EXITTRANSITION()); + transition.resize(num_classes); + for (int i = 0; i < num_classes; i++) { + transition[i].assign(num_classes, + 1. / static_cast<double>(num_classes)); + } +} + +void xmm::HierarchicalHMM::updateExitProbabilities() { + for (auto &model : models) { + model.second.updateExitProbabilities(); + } +} + +void xmm::HierarchicalHMM::addModelForClass(std::string const &label) { + Model<SingleClassHMM, HMM>::addModelForClass(label); + updateTransitionParameters(); +} + +void xmm::HierarchicalHMM::forward_init(std::vector<float> const &observation) { + checkTraining(); + double norm_const(0.0); + + int model_index(0); + for (auto &model : models) { + unsigned int N = model.second.parameters.states.get(); + + for (int i = 0; i < 3; i++) { + model.second.alpha_h[i].assign(N, 0.0); + } + + // Compute Emission probability and initialize on the first state of + // the + // primitive + if (model.second.parameters.transition_mode.get() == + HMM::TransitionMode::Ergodic) { + for (int i = 0; i < model.second.parameters.states.get(); i++) { + if (shared_parameters->bimodal.get()) { + model.second.alpha_h[0][i] = + model.second.prior[i] * + model.second.states[i].obsProb_input(&observation[0]); + } else { + model.second.alpha_h[0][i] = + model.second.prior[i] * + model.second.states[i].obsProb(&observation[0]); + } + model.second.results.instant_likelihood += + model.second.alpha_h[0][i]; + } + } else { + model.second.alpha_h[0][0] = this->prior[model_index]; + if (shared_parameters->bimodal.get()) { + model.second.alpha_h[0][0] *= + model.second.states[0].obsProb_input(&observation[0]); + } else { + model.second.alpha_h[0][0] *= + model.second.states[0].obsProb(&observation[0]); + } + model.second.results.instant_likelihood = + model.second.alpha_h[0][0]; + } + norm_const += model.second.results.instant_likelihood; + model_index++; + } + + // Normalize Alpha variables + for (auto &model : models) { + unsigned int N = model.second.parameters.states.get(); + for (unsigned int e = 0; e < 3; e++) + for (unsigned int k = 0; k < N; k++) + model.second.alpha_h[e][k] /= norm_const; + } + + forward_initialized_ = true; +} + +void xmm::HierarchicalHMM::forward_update( + std::vector<float> const &observation) { + checkTraining(); + double norm_const(0.0); + + // Frontier Algorithm: variables + double tmp(0); + std::vector<double> + front; // frontier variable : intermediate computation variable + + // Intermediate variables: compute the sum of probabilities of making a + // transition to a new primitive + likelihoodAlpha(1, frontier_v1_); + likelihoodAlpha(2, frontier_v2_); + + int num_classes = static_cast<int>(size()); + + // FORWARD UPDATE + // -------------------------------------- + int dst_model_index(0); + for (auto &dstModel : models) { + unsigned int N = dstModel.second.parameters.states.get(); + + // 1) COMPUTE FRONTIER VARIABLE + // -------------------------------------- + front.assign(N, 0.0); + + if (dstModel.second.parameters.transition_mode.get() == + HMM::TransitionMode::Ergodic) { + for (int k = 0; k < N; ++k) { + for (unsigned int j = 0; j < N; ++j) { + front[k] += dstModel.second.transition[j * N + k] / + (1 - dstModel.second.exit_probabilities_[j]) * + dstModel.second.alpha_h[0][j]; + } + + for (int src_model_index = 0; src_model_index < num_classes; + src_model_index++) { + front[k] += dstModel.second.prior[k] * + (frontier_v1_[src_model_index] * + this->transition[src_model_index] + [dst_model_index] + + this->prior[dst_model_index] * + frontier_v2_[src_model_index]); + } + } + } else { + // k=0: first state of the primitive + front[0] = + dstModel.second.transition[0] * dstModel.second.alpha_h[0][0]; + + for (int src_model_index = 0; src_model_index < num_classes; + src_model_index++) { + front[0] += frontier_v1_[src_model_index] * + transition[src_model_index][dst_model_index] + + this->prior[dst_model_index] * + frontier_v2_[src_model_index]; + } + + // k>0: rest of the primitive + for (int k = 1; k < N; ++k) { + front[k] += dstModel.second.transition[k * 2] / + (1 - dstModel.second.exit_probabilities_[k]) * + dstModel.second.alpha_h[0][k]; + front[k] += dstModel.second.transition[(k - 1) * 2 + 1] / + (1 - dstModel.second.exit_probabilities_[k - 1]) * + dstModel.second.alpha_h[0][k - 1]; + } + + for (int i = 0; i < 3; i++) { + for (int k = 0; k < N; k++) { + dstModel.second.alpha_h[i][k] = 0.0; + } + } + } + + // 2) UPDATE FORWARD VARIABLE + // -------------------------------------- + + dstModel.second.results.exit_likelihood = 0.0; + dstModel.second.results.instant_likelihood = 0.0; + + // end of the primitive: handle exit states + for (int k = 0; k < N; ++k) { + if (shared_parameters->bimodal.get()) + tmp = dstModel.second.states[k].obsProb_input(&observation[0]) * + front[k]; + else + tmp = dstModel.second.states[k].obsProb(&observation[0]) * + front[k]; + + dstModel.second.alpha_h[2][k] = + this->exit_transition[dst_model_index] * + dstModel.second.exit_probabilities_[k] * tmp; + dstModel.second.alpha_h[1][k] = + (1 - this->exit_transition[dst_model_index]) * + dstModel.second.exit_probabilities_[k] * tmp; + dstModel.second.alpha_h[0][k] = + (1 - dstModel.second.exit_probabilities_[k]) * tmp; + + dstModel.second.results.exit_likelihood += + dstModel.second.alpha_h[1][k] + dstModel.second.alpha_h[2][k]; + dstModel.second.results.instant_likelihood += + dstModel.second.alpha_h[0][k] + dstModel.second.alpha_h[1][k] + + dstModel.second.alpha_h[2][k]; + + norm_const += tmp; + } + + dstModel.second.results.exit_ratio = + dstModel.second.results.exit_likelihood / + dstModel.second.results.instant_likelihood; + + dst_model_index++; + } + + // Normalize Alpha variables + for (auto &model : models) { + unsigned int N = model.second.parameters.states.get(); + for (unsigned int e = 0; e < 3; e++) + for (unsigned int k = 0; k < N; k++) + model.second.alpha_h[e][k] /= norm_const; + } +} + +void xmm::HierarchicalHMM::likelihoodAlpha( + int exitNum, std::vector<double> &likelihoodVector) const { + if (exitNum < 0) { // Likelihood over all exit states + unsigned int l(0); + for (auto &model : models) { + likelihoodVector[l] = 0.0; + for (unsigned int exit = 0; exit < 3; ++exit) { + for (unsigned int k = 0; + k < model.second.parameters.states.get(); k++) { + likelihoodVector[l] += model.second.alpha_h[exit][k]; + } + } + l++; + } + + } else { // Likelihood for exit state "exitNum" + unsigned int l(0); + for (auto &model : models) { + likelihoodVector[l] = 0.0; + for (unsigned int k = 0; k < model.second.parameters.states.get(); + k++) { + likelihoodVector[l] += model.second.alpha_h[exitNum][k]; + } + l++; + } + } +} + +void xmm::HierarchicalHMM::removeClass(std::string const &label) { + Model<SingleClassHMM, HMM>::removeClass(label); + updateTransitionParameters(); +} + +void xmm::HierarchicalHMM::reset() { + Model<SingleClassHMM, HMM>::reset(); + results.instant_likelihoods.resize(size()); + results.instant_normalized_likelihoods.resize(size()); + results.smoothed_likelihoods.resize(size()); + results.smoothed_normalized_likelihoods.resize(size()); + results.smoothed_log_likelihoods.resize(size()); + if (shared_parameters->bimodal.get()) { + unsigned int dimension_output = + shared_parameters->dimension.get() - + shared_parameters->dimension_input.get(); + results.output_values.resize(dimension_output); + results.output_covariance.assign( + (configuration.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) + ? dimension_output * dimension_output + : dimension_output, + 0.0); + } + frontier_v1_.resize(this->size()); + frontier_v2_.resize(this->size()); + forward_initialized_ = false; + for (auto &model : models) { + model.second.is_hierarchical_ = configuration.hierarchical.get(); + model.second.reset(); + } +} + +void xmm::HierarchicalHMM::filter(std::vector<float> const &observation) { + checkTraining(); + if (configuration.hierarchical.get()) { + if (forward_initialized_) { + this->forward_update(observation); + } else { + this->forward_init(observation); + } + } else { + int i(0); + for (auto &model : models) { + results.instant_likelihoods[i] = model.second.filter(observation); + i++; + } + } + + // Compute time progression + for (auto &model : models) { + model.second.updateAlphaWindow(); + model.second.updateResults(); + } + updateResults(); + + if (shared_parameters->bimodal.get()) { + unsigned int dimension = shared_parameters->dimension.get(); + unsigned int dimension_input = shared_parameters->dimension_input.get(); + unsigned int dimension_output = dimension - dimension_input; + + for (auto &model : models) { + model.second.regression(observation); + } + + if (configuration.multiClass_regression_estimator == + MultiClassRegressionEstimator::Likeliest) { + results.output_values = + this->models[results.likeliest].results.output_values; + results.output_covariance = + this->models[results.likeliest].results.output_covariance; + } else { + results.output_values.assign(dimension_output, 0.0); + results.output_covariance.assign( + (configuration.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) + ? dimension_output * dimension_output + : dimension_output, + 0.0); + + int i(0); + for (auto &model : models) { + for (int d = 0; d < dimension_output; d++) { + results.output_values[d] += + results.smoothed_normalized_likelihoods[i] * + model.second.results.output_values[d]; + + if ((configuration.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full)) { + for (int d2 = 0; d2 < dimension_output; d2++) + results + .output_covariance[d * dimension_output + d2] += + results.smoothed_normalized_likelihoods[i] * + model.second.results + .output_covariance[d * dimension_output + + d2]; + } else { + results.output_covariance[d] += + results.smoothed_normalized_likelihoods[i] * + model.second.results.output_covariance[d]; + } + } + i++; + } + } + } +} + +void xmm::HierarchicalHMM::updateResults() { + double maxlog_likelihood = 0.0; + double normconst_instant(0.0); + double normconst_smoothed(0.0); + int i(0); + for (auto &model : models) { + results.instant_likelihoods[i] = + model.second.results.instant_likelihood; + results.smoothed_log_likelihoods[i] = + model.second.results.log_likelihood; + results.smoothed_likelihoods[i] = + exp(results.smoothed_log_likelihoods[i]); + + results.instant_normalized_likelihoods[i] = + results.instant_likelihoods[i]; + results.smoothed_normalized_likelihoods[i] = + results.smoothed_likelihoods[i]; + + normconst_instant += results.instant_normalized_likelihoods[i]; + normconst_smoothed += results.smoothed_normalized_likelihoods[i]; + + if (i == 0 || results.smoothed_log_likelihoods[i] > maxlog_likelihood) { + maxlog_likelihood = results.smoothed_log_likelihoods[i]; + results.likeliest = model.first; + } + i++; + } + + i = 0; + for (auto it = this->models.begin(); it != this->models.end(); ++it, ++i) { + results.instant_normalized_likelihoods[i] /= normconst_instant; + results.smoothed_normalized_likelihoods[i] /= normconst_smoothed; + } +} + +Json::Value xmm::HierarchicalHMM::toJson() const { + checkTraining(); + Json::Value root = Model<SingleClassHMM, HMM>::toJson(); + root["prior"] = vector2json(prior); + // int num_models = static_cast<int>(size()); + // std::vector<double> transition_flat(num_models * num_models, 0.0); + // for (int i = 0; i < num_models; i++) { + // for (int j = 0; j < num_models; j++) { + // transition_flat[i * num_models + j] = transition[i][j]; + // } + // } + root["transition"].resize(static_cast<Json::ArrayIndex>(size())); + for (int i = 0; i < size(); i++) { + root["transition"][i] = vector2json(transition[i]); + } + root["exit_transition"] = vector2json(exit_transition); + + return root; +} + +void xmm::HierarchicalHMM::fromJson(Json::Value const &root) { + checkTraining(); + try { + HierarchicalHMM tmp(root); + *this = tmp; + } catch (JsonException &e) { + throw e; + } +} + +// void xmm::HierarchicalHMM::makeBimodal(unsigned int dimension_input) +//{ +// checkTraining(); +// if (bimodal_) +// throw std::runtime_error("The model is already bimodal"); +// if (dimension_input >= dimension()) +// throw std::out_of_range("Request input dimension exceeds the current +// dimension"); +// +// try { +// this->referenceModel_.makeBimodal(dimension_input); +// } catch (std::exception const& e) { +// } +// bimodal_ = true; +// for (model_iterator it=this->models.begin(); it != this->models.end(); +// ++it) { +// model.second.makeBimodal(dimension_input); +// } +// set_trainingSet(NULL); +// results.output_values.resize(dimension() - this->dimension_input()); +// results.output_variance.resize(dimension() - this->dimension_input()); +//} +// +// void xmm::HierarchicalHMM::makeUnimodal() +//{ +// checkTraining(); +// if (!bimodal_) +// throw std::runtime_error("The model is already unimodal"); +// this->referenceModel_.makeUnimodal(); +// for (model_iterator it=this->models.begin(); it != this->models.end(); +// ++it) { +// model.second.makeUnimodal(); +// } +// set_trainingSet(NULL); +// results.output_values.clear(); +// results.output_variance.clear(); +// bimodal_ = false; +//} +// +// xmm::HierarchicalHMM +// xmm::HierarchicalHMM::extractSubmodel(std::vector<unsigned int>& columns) +// const +//{ +// checkTraining(); +// if (columns.size() > this->dimension()) +// throw std::out_of_range("requested number of columns exceeds the +// dimension of the current model"); +// for (unsigned int column=0; column<columns.size(); ++column) { +// if (columns[column] >= this->dimension()) +// throw std::out_of_range("Some column indices exceeds the dimension +// of the current model"); +// } +// HierarchicalHMM target_model(*this); +// target_model.set_trainingSet(NULL); +// target_model.bimodal_ = false; +// target_model.referenceModel_ = +// this->referenceModel_.extractSubmodel(columns); +// for (model_iterator it=target_model.models.begin(); it != +// target_model.models.end(); ++it) { +// model.second = this->models.at(model.first).extractSubmodel(columns); +// } +// return target_model; +//} +// +// xmm::HierarchicalHMM xmm::HierarchicalHMM::extractSubmodel_input() const +//{ +// checkTraining(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_input(dimension_input()); +// for (unsigned int i=0; i<dimension_input(); ++i) { +// columns_input[i] = i; +// } +// return extractSubmodel(columns_input); +//} +// +// xmm::HierarchicalHMM xmm::HierarchicalHMM::extractSubmodel_output() const +//{ +// checkTraining(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_output(dimension() - dimension_input()); +// for (unsigned int i=dimension_input(); i<dimension(); ++i) { +// columns_output[i-dimension_input()] = i; +// } +// return extractSubmodel(columns_output); +//} +// +// xmm::HierarchicalHMM xmm::HierarchicalHMM::extract_inverse_model() const +//{ +// checkTraining(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns(dimension()); +// for (unsigned int i=0; i<dimension()-dimension_input(); ++i) { +// columns[i] = i+dimension_input(); +// } +// for (unsigned int i=dimension()-dimension_input(), j=0; i<dimension(); +// ++i, +// ++j) { +// columns[i] = j; +// } +// HierarchicalHMM target_model = extractSubmodel(columns); +// target_model.makeBimodal(dimension()-dimension_input()); +// return target_model; +//} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHierarchicalHmm.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHierarchicalHmm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..849850b7157598b91c03b87d70efb4015badc4e7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHierarchicalHmm.hpp @@ -0,0 +1,313 @@ +/* + * hierarchical_hmm.h + * + * Hierarchical Hidden Markov Model for Continuous Recognition and Regression + * (Multi-class) + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmm_lib_hierarchical_hmm_h +#define xmm_lib_hierarchical_hmm_h + +#include "../../core/model/xmmModel.hpp" +#include "../gmm/xmmGmm.hpp" +#include "xmmHmmSingleClass.hpp" + +namespace xmm { +/** + @ingroup HMM + @brief Hierarchical Hidden Markov Model for Continuous Recognition and + Regression (Multi-class) + */ +class HierarchicalHMM : public Model<SingleClassHMM, HMM> { + public: + /** + @brief Default exit transition for the highest level + */ + static const double DEFAULT_EXITTRANSITION() { return 0.1; } + + /** + @brief Constructor + @param bimodal specifies if the model should be used for regression + */ + HierarchicalHMM(bool bimodal = false); + + /** + @brief Copy Constructor + @param src Source Model + */ + HierarchicalHMM(HierarchicalHMM const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit HierarchicalHMM(Json::Value const& root); + + /** + @brief Assignment + @param src Source Model + */ + HierarchicalHMM& operator=(HierarchicalHMM const& src); + + /** @name Class Manipulation */ + ///@{ + + /** + @brief Remove a specific class by label + @param label label of the class to remove + */ + virtual void removeClass(std::string const& label); + + /** + @brief Remove All models + */ + virtual void clear(); + + ///@} + + /** @name Accessors */ + ///@{ + + void addExitPoint(int state, float proba); + + ///@} + + /** @name Performance */ + ///@{ + + /** + @brief Resets the fitering process (recognition or regression) + */ + virtual void reset(); + + /** + @brief filters a incoming observation (performs recognition or regression) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + */ + virtual void filter(std::vector<float> const& observation); + + ///@} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root); + + ///@} + + // /** + // @brief Convert to bimodal HierarchicalHMM in place + // @param dimension_input dimension of the input modality + // @throws runtime_error if the model is already bimodal + // @throws out_of_range if the requested input dimension is too + // large + // */ + // void makeBimodal(unsigned int dimension_input); + // + // /** + // @brief Convert to unimodal HierarchicalHMM in place + // @throws runtime_error if the model is already unimodal + // */ + // void makeUnimodal(); + // + // /** + // @brief extract a submodel with the given columns + // @param columns columns indices in the target order + // @throws runtime_error if the model is training + // @throws out_of_range if the number or indices of the requested + // columns exceeds the current dimension + // @return a HierarchicalHMM from the current model considering only + // the target columns + // */ + // HierarchicalHMM extractSubmodel(std::vector<unsigned int>& + // columns) + // const; + // + // /** + // @brief extract the submodel of the input modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal GMM of the input modality from the current + // bimodal model + // */ + // HierarchicalHMM extractSubmodel_input() const; + // + // /** + // @brief extract the submodel of the output modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal HierarchicalHMM of the output modality from + // the current bimodal model + // */ + // HierarchicalHMM extractSubmodel_output() const; + // + // /** + // @brief extract the model with reversed input and output + // modalities + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a bimodal HierarchicalHMM that swaps the input and + // output modalities + // */ + // HierarchicalHMM extract_inverse_model() const; + + /** + @brief Results of the Filtering Process (Recognition + Regression) + */ + Results<HMM> results; + + /** + @brief Prior probabilities of the models + */ + std::vector<double> prior; + + /** + @brief exit probabilities of the model (probability to finish and go back + to the root) + */ + std::vector<double> exit_transition; + + /** + @brief Transition probabilities between models + */ + std::vector<std::vector<double>> transition; + + protected: + /** + @brief Finishes the background training process by joining threads and + deleting the models which training failed + @details: updates transition parameters after joining + */ + virtual void joinTraining(); + + /** + @brief update high-level parameters when a new primitive is learned + @details updated parameters: prior probabilities + transition matrix + */ + void updateTransitionParameters(); + + /** + @brief ergodic learning update high-level prior probabilities -> equal + prior probs + */ + void updatePrior(); + + /** + @brief ergodic learning: update high-level transition matrix + @details equal transition probabilities between primitive gestures + */ + void updateTransition(); + + /** + @brief Update exit probabilities of each sub-model + */ + void updateExitProbabilities(); + + virtual void addModelForClass(std::string const& label); + + /** + @brief Normalize segment level prior and transition matrices + */ + void normalizeTransitions(); + + /** + @brief Initialization of the Forward Algorithm for the hierarchical HMM. + see: Jules Francoise. Realtime Segmentation and Recognition of Gestures + using Hierarchical Markov Models. Master’s Thesis, Université Pierre et + Marie Curie, Ircam, 2011. + [http://articles.ircam.fr/textes/Francoise11a/index.pdf] + @param observation observation vector. If the model is bimodal, this should + be allocated for + both modalities, and should contain the observation on the input modality. + The predicted + output will be appended to the input modality observation + */ + void forward_init(std::vector<float> const& observation); + + /** + @brief Update of the Forward Algorithm for the hierarchical HMM. + see: Jules Francoise. Realtime Segmentation and Recognition of Gestures + using Hierarchical Markov Models. Master’s Thesis, Université Pierre et + Marie Curie, Ircam, 2011. + [http://articles.ircam.fr/textes/Francoise11a/index.pdf] + @param observation observation vector. If the model is bimodal, this should + be allocated for + both modalities, and should contain the observation on the input modality. + The predicted + output will be appended to the input modality observation + */ + void forward_update(std::vector<float> const& observation); + + /** + @brief get instantaneous likelihood + * + get instantaneous likelihood on alpha variable for exit state exitNum. + @param exitNum number of exit state (0=continue, 1=transition, 2=back to + root). if -1, get likelihood over all exit states + @param likelihoodVector likelihood vector (size nbPrimitives) + */ + void likelihoodAlpha(int exitNum, + std::vector<double>& likelihoodVector) const; + + /** + @brief Update the results (Likelihoods) + */ + void updateResults(); + + /** + @brief Defines if the forward algorithm has been initialized + */ + bool forward_initialized_; + + /** + @brief intermediate Forward variable (used in Frontier algorithm) + */ + std::vector<double> frontier_v1_; + + /** + @brief intermediate Forward variable (used in Frontier algorithm) + */ + std::vector<double> frontier_v2_; +}; +} + +#endif \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmParameters.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmParameters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e4711a72a9ad807c6b700d7e0869b72e3bab7fe --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmParameters.cpp @@ -0,0 +1,199 @@ +/* + * xmmHmmParameters.cpp + * + * Parameters of Hidden Markov Models + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmHmmParameters.hpp" + +xmm::ClassParameters<xmm::HMM>::ClassParameters() + : changed(true), + states(10, 1), + gaussians(1, 1), + relative_regularization(1.0e-2, 1e-20), + absolute_regularization(1.0e-3, 1e-20), + covariance_mode(GaussianDistribution::CovarianceMode::Full), + transition_mode(HMM::TransitionMode::LeftRight), + regression_estimator(HMM::RegressionEstimator::Full), + hierarchical(true) { + states.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + transition_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + regression_estimator.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + hierarchical.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); +} + +xmm::ClassParameters<xmm::HMM>::ClassParameters(ClassParameters<HMM> const& src) + : changed(true), + states(src.states), + gaussians(src.gaussians), + relative_regularization(src.relative_regularization), + absolute_regularization(src.absolute_regularization), + covariance_mode(src.covariance_mode), + transition_mode(src.transition_mode), + regression_estimator(src.regression_estimator), + hierarchical(src.hierarchical) { + states.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + transition_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + regression_estimator.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + hierarchical.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); +} + +xmm::ClassParameters<xmm::HMM>::ClassParameters(Json::Value const& root) + : ClassParameters() { + states.set(root["states"].asInt()); + gaussians.set(root["gaussians"].asInt()); + relative_regularization.set(root["relative_regularization"].asFloat()); + absolute_regularization.set(root["absolute_regularization"].asFloat()); + covariance_mode.set(static_cast<GaussianDistribution::CovarianceMode>( + root["covariance_mode"].asInt())); + transition_mode.set( + static_cast<HMM::TransitionMode>(root["transition_mode"].asInt())); + regression_estimator.set(static_cast<HMM::RegressionEstimator>( + root["regression_estimator"].asInt())); + hierarchical.set(root["hierarchical"].asBool()); +} + +xmm::ClassParameters<xmm::HMM>& xmm::ClassParameters<xmm::HMM>::operator=( + ClassParameters<HMM> const& src) { + if (this != &src) { + changed = true; + states = src.states; + gaussians = src.gaussians; + relative_regularization = src.relative_regularization; + absolute_regularization = src.absolute_regularization; + covariance_mode = src.covariance_mode; + transition_mode = src.transition_mode; + regression_estimator = src.regression_estimator; + states.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + gaussians.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + relative_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + absolute_regularization.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + covariance_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + transition_mode.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + regression_estimator.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + hierarchical.onAttributeChange( + this, &xmm::ClassParameters<xmm::HMM>::onAttributeChange); + } + return *this; +} + +Json::Value xmm::ClassParameters<xmm::HMM>::toJson() const { + Json::Value root; + root["states"] = static_cast<int>(states.get()); + root["gaussians"] = static_cast<int>(gaussians.get()); + root["relative_regularization"] = relative_regularization.get(); + root["absolute_regularization"] = absolute_regularization.get(); + root["covariance_mode"] = static_cast<int>(covariance_mode.get()); + root["transition_mode"] = static_cast<int>(transition_mode.get()); + root["regression_estimator"] = static_cast<int>(regression_estimator.get()); + root["hierarchical"] = hierarchical.get(); + return root; +} + +void xmm::ClassParameters<xmm::HMM>::fromJson(Json::Value const& root) { + try { + ClassParameters<HMM> tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +void xmm::ClassParameters<xmm::HMM>::onAttributeChange( + AttributeBase* attr_pointer) { + changed = true; + attr_pointer->changed = false; +} + +template <> +void xmm::checkLimits<xmm::HMM::TransitionMode>( + xmm::HMM::TransitionMode const& value, + xmm::HMM::TransitionMode const& limit_min, + xmm::HMM::TransitionMode const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error( + "Attribute value out of range. Range: [" + + std::to_string(static_cast<int>(limit_min)) + " ; " + + std::to_string(static_cast<int>(limit_max)) + "]"); +} + +template <> +xmm::HMM::TransitionMode +xmm::Attribute<xmm::HMM::TransitionMode>::defaultLimitMax() { + return xmm::HMM::TransitionMode::LeftRight; +} + +template <> +void xmm::checkLimits<xmm::HMM::RegressionEstimator>( + xmm::HMM::RegressionEstimator const& value, + xmm::HMM::RegressionEstimator const& limit_min, + xmm::HMM::RegressionEstimator const& limit_max) { + if (value < limit_min || value > limit_max) + throw std::domain_error( + "Attribute value out of range. Range: [" + + std::to_string(static_cast<int>(limit_min)) + " ; " + + std::to_string(static_cast<int>(limit_max)) + "]"); +} + +template <> +xmm::HMM::RegressionEstimator +xmm::Attribute<xmm::HMM::RegressionEstimator>::defaultLimitMax() { + return xmm::HMM::RegressionEstimator::Likeliest; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmParameters.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmParameters.hpp new file mode 100644 index 0000000000000000000000000000000000000000..326162bc05e66afa04cdf54f6e3bcc0964896be7 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmParameters.hpp @@ -0,0 +1,208 @@ +/* + * xmmHmmParameters.hpp + * + * Parameters of Hidden Markov Models + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmHmmParameters_hpp +#define xmmHmmParameters_hpp + +#include "../../core/distributions/xmmGaussianDistribution.hpp" +#include "../../core/model/xmmModelParameters.hpp" + +namespace xmm { +/** + @defgroup HMM [Models] Hidden Markov Models + */ +class HMM { + public: + /** + @brief Type of Transition Matrix + */ + enum class TransitionMode { + /** + @brief Ergodic Transition Matrix + */ + Ergodic = 0, + + /** + @brief Left-Right Transition model + @details The only authorized transitions are: auto-transition and + transition to the next state + */ + LeftRight = 1 + }; + + /** + @enum RegressionEstimator + @brief Estimator for the regression with HMMs + */ + enum class RegressionEstimator { + /** + @brief The output is estimated by a weighted regression over all states + */ + Full = 0, + + /** + @brief The output is estimated by a weighted regression over a window + centered around + the likeliest state + */ + Windowed = 1, + + /** + @brief The output is estimated by a regression using the likeliest + state only. + */ + Likeliest = 2 + }; +}; + +/** + @ingroup HMM + @brief Parameters specific to each class of a Hidden Markov Model + */ +template <> +class ClassParameters<HMM> { + public: + /** + @brief Default Constructor + */ + ClassParameters(); + + /** + @brief Copy Constructor + @param src Source Object + */ + ClassParameters(ClassParameters const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit ClassParameters(Json::Value const& root); + + /** + @brief Assignment + @param src Source Object + */ + ClassParameters& operator=(ClassParameters const& src); + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root); + + ///@} + + /** + @brief specifies if parameters have changed (model is invalid) + */ + bool changed = false; + + /** + @brief Number of hidden states + */ + Attribute<unsigned int> states; + + /** + @brief Number of Gaussian Mixture Components + */ + Attribute<unsigned int> gaussians; + + /** + @brief Offset Added to the diagonal of covariance matrices for convergence + (Relative to Data Variance) + */ + Attribute<double> relative_regularization; + + /** + @brief Offset Added to the diagonal of covariance matrices for convergence + (minimum value) + */ + Attribute<double> absolute_regularization; + + /** + @brief Covariance Mode + */ + Attribute<GaussianDistribution::CovarianceMode> covariance_mode; + + /** + @brief Transition matrix of the model (left-right vs ergodic) + */ + Attribute<HMM::TransitionMode> transition_mode; + + /** + @brief Type of regression estimator + */ + Attribute<HMM::RegressionEstimator> regression_estimator; + + /** + @brief specifies if the decoding algorithm is hierarchical or + class-conditional + */ + Attribute<bool> hierarchical; + + protected: + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); +}; + +template <> +void checkLimits<HMM::TransitionMode>(HMM::TransitionMode const& value, + HMM::TransitionMode const& limit_min, + HMM::TransitionMode const& limit_max); + +template <> +HMM::TransitionMode Attribute<HMM::TransitionMode>::defaultLimitMax(); + +template <> +void checkLimits<HMM::RegressionEstimator>( + HMM::RegressionEstimator const& value, + HMM::RegressionEstimator const& limit_min, + HMM::RegressionEstimator const& limit_max); + +template <> +HMM::RegressionEstimator Attribute<HMM::RegressionEstimator>::defaultLimitMax(); +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmResults.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmResults.hpp new file mode 100644 index 0000000000000000000000000000000000000000..633df90d4e85496ae1e8a78c56d47b730d572f95 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmResults.hpp @@ -0,0 +1,93 @@ +/* + * xmmHmmResults.hpp + * + * Results of Hidden Markov Models for a single class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmHmmResults_hpp +#define xmmHmmResults_hpp + +#include "../../core/model/xmmModelResults.hpp" + +namespace xmm { +/** + @ingroup HMM + @brief Results of Hidden Markov Models for a single class + */ +template <> +struct ClassResults<HMM> { + /** + @brief Instantaneous likelihood + */ + double instant_likelihood; + + /** + @brief Cumulative log-likelihood computed on a sliding window + */ + double log_likelihood; + + /** + @brief Predicted Output parameter vector (only used in regression mode) + @warning this variable only allocated if the model is bimodal + */ + std::vector<float> output_values; + + /** + @brief Predicted Output covariance associated with the generated parameter + vector (only used in regression mode) + @warning this variable only allocated if the model is bimodal + */ + std::vector<float> output_covariance; + + /** + @brief Estimated time progression. + @details The time progression is computed as the centroid of the state + probability distribution estimated by the forward algorithm + */ + double progress; + + /** + @brief Likelihood to exit the gesture on the next time step + */ + double exit_likelihood; + + /** + @brief Likelihood to exit the gesture on the next time step (normalized -/- + total likelihood) + */ + double exit_ratio; + + /** + @brief Index of the likeliest state + */ + unsigned int likeliest_state; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmSingleClass.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmSingleClass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a14d696e7dc7492c8d87678062ac731187d07cc --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmSingleClass.cpp @@ -0,0 +1,1480 @@ +/* + * xmmHmmSingleClass.cpp + * + * Hidden Markov Model Definition for a Single Class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmHmmSingleClass.hpp" + +xmm::SingleClassHMM::SingleClassHMM(std::shared_ptr<SharedParameters> p) + : SingleClassProbabilisticModel(p), is_hierarchical_(true) {} + +xmm::SingleClassHMM::SingleClassHMM(SingleClassHMM const& src) + : SingleClassProbabilisticModel(src), + parameters(src.parameters), + states(src.states), + prior(src.prior), + transition(src.transition), + is_hierarchical_(src.is_hierarchical_), + exit_probabilities_(src.exit_probabilities_) { + alpha.resize(parameters.states.get()); + previous_alpha_.resize(parameters.states.get()); + beta_.resize(parameters.states.get()); + previous_beta_.resize(parameters.states.get()); +} + +xmm::SingleClassHMM::SingleClassHMM(std::shared_ptr<SharedParameters> p, + Json::Value const& root) + : SingleClassProbabilisticModel(p, root), is_hierarchical_(true) { + parameters.fromJson(root["parameters"]); + + allocate(); + + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + json2vector(root["prior"], prior, parameters.states.get()); + json2vector(root["transition"], transition, + parameters.states.get() * parameters.states.get()); + } else { + json2vector(root["transition"], transition, + 2 * parameters.states.get()); + } + if (root.isMember("exitProbabilities")) { + json2vector(root["exitProbabilities"], exit_probabilities_, + parameters.states.get()); + } + + int s(0); + for (auto p : root["states"]) { + states[s++].fromJson(p); + } +} + +xmm::SingleClassHMM& xmm::SingleClassHMM::operator=(SingleClassHMM const& src) { + if (this != &src) { + SingleClassProbabilisticModel::operator=(src); + + is_hierarchical_ = src.is_hierarchical_; + parameters = src.parameters; + transition = src.transition; + prior = src.prior; + exit_probabilities_ = src.exit_probabilities_; + states = src.states; + + alpha.resize(parameters.states.get()); + previous_alpha_.resize(parameters.states.get()); + beta_.resize(parameters.states.get()); + previous_beta_.resize(parameters.states.get()); + } + return *this; +} + +#pragma mark - +#pragma mark Parameters initialization +void xmm::SingleClassHMM::allocate() { + unsigned int numStates = parameters.states.get(); + + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + prior.resize(numStates); + transition.resize(numStates * numStates); + } else { + prior.clear(); + transition.resize(numStates * 2); + } + alpha.resize(numStates); + previous_alpha_.resize(numStates); + beta_.resize(numStates); + previous_beta_.resize(numStates); + SingleClassGMM tmpGMM(shared_parameters); + tmpGMM.parameters.gaussians.set(parameters.gaussians.get()); + tmpGMM.parameters.relative_regularization.set( + parameters.relative_regularization.get()); + tmpGMM.parameters.absolute_regularization.set( + parameters.absolute_regularization.get()); + tmpGMM.parameters.covariance_mode.set(parameters.covariance_mode.get()); + states.assign(numStates, tmpGMM); + for (auto& state : states) { + state.allocate(); + } + if (is_hierarchical_) updateExitProbabilities(NULL); +} + +void xmm::SingleClassHMM::initParametersToDefault( + std::vector<float> const& dataStddev) { + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + setErgodic(); + } else { + setLeftRight(); + } + for (int i = 0; i < parameters.states.get(); i++) { + states[i].initParametersToDefault(dataStddev); + } +} + +void xmm::SingleClassHMM::initMeansWithAllPhrases(TrainingSet* trainingSet) { + if (!trainingSet || trainingSet->empty()) return; + int dimension = static_cast<int>(shared_parameters->dimension.get()); + unsigned int numStates = parameters.states.get(); + + for (int n = 0; n < numStates; n++) + for (int d = 0; d < dimension; d++) + states[n].components[0].mean[d] = 0.0; + + std::vector<int> factor(numStates, 0); + for (auto phrase_it = trainingSet->begin(); phrase_it != trainingSet->end(); + phrase_it++) { + unsigned int step = phrase_it->second->size() / numStates; + unsigned int offset(0); + for (unsigned int n = 0; n < numStates; n++) { + for (unsigned int t = 0; t < step; t++) { + for (unsigned int d = 0; d < dimension; d++) { + states[n].components[0].mean[d] += + phrase_it->second->getValue(offset + t, d); + } + } + offset += step; + factor[n] += step; + } + } + + for (int n = 0; n < numStates; n++) + for (int d = 0; d < dimension; d++) + states[n].components[0].mean[d] /= factor[n]; +} + +void xmm::SingleClassHMM::initCovariances_fullyObserved( + TrainingSet* trainingSet) { + // TODO: simplify with covariance symmetricity. + if (!trainingSet || trainingSet->empty()) return; + int dimension = static_cast<int>(shared_parameters->dimension.get()); + unsigned int numStates = parameters.states.get(); + + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int n = 0; n < numStates; n++) + states[n].components[0].covariance.assign(dimension * dimension, + 0.0); + } else { + for (int n = 0; n < numStates; n++) + states[n].components[0].covariance.assign(dimension, 0.0); + } + + std::vector<int> factor(numStates, 0); + std::vector<double> othermeans(numStates * dimension, 0.0); + for (auto phrase_it = trainingSet->begin(); phrase_it != trainingSet->end(); + phrase_it++) { + unsigned int step = phrase_it->second->size() / numStates; + unsigned int offset(0); + for (unsigned int n = 0; n < numStates; n++) { + for (unsigned int t = 0; t < step; t++) { + for (unsigned int d1 = 0; d1 < dimension; d1++) { + othermeans[n * dimension + d1] += + phrase_it->second->getValue(offset + t, d1); + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension; d2++) { + states[n].components[0].covariance[d1 * dimension + + d2] += + phrase_it->second->getValue(offset + t, d1) * + phrase_it->second->getValue(offset + t, d2); + } + } else { + float value = + phrase_it->second->getValue(offset + t, d1); + states[n].components[0].covariance[d1] += value * value; + } + } + } + offset += step; + factor[n] += step; + } + } + + for (unsigned int n = 0; n < numStates; n++) + for (unsigned int d1 = 0; d1 < dimension; d1++) { + othermeans[n * dimension + d1] /= factor[n]; + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension; d2++) + states[n].components[0].covariance[d1 * dimension + d2] /= + factor[n]; + } else { + states[n].components[0].covariance[d1] /= factor[n]; + } + } + + for (int n = 0; n < numStates; n++) { + for (int d1 = 0; d1 < dimension; d1++) { + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension; d2++) + states[n].components[0].covariance[d1 * dimension + d2] -= + othermeans[n * dimension + d1] * + othermeans[n * dimension + d2]; + } else { + states[n].components[0].covariance[d1] -= + othermeans[n * dimension + d1] * + othermeans[n * dimension + d1]; + } + } + states[n].addCovarianceOffset(); + states[n].updateInverseCovariances(); + } +} + +void xmm::SingleClassHMM::initMeansCovariancesWithGMMEM( + TrainingSet* trainingSet) { + unsigned int numStates = parameters.states.get(); + + for (unsigned int n = 0; n < numStates; n++) { + TrainingSet temp_ts(MemoryMode::SharedMemory, + shared_parameters->bimodal.get() + ? Multimodality::Bimodal + : Multimodality::Unimodal); + temp_ts.dimension.set(shared_parameters->dimension.get()); + temp_ts.dimension_input.set(shared_parameters->dimension_input.get()); + for (auto phrase_it = trainingSet->begin(); + phrase_it != trainingSet->end(); phrase_it++) { + unsigned int step = phrase_it->second->size() / numStates; + if (step == 0) continue; + temp_ts.addPhrase(phrase_it->first, label); + if (shared_parameters->bimodal.get()) + temp_ts.getPhrase(phrase_it->first) + ->connect(phrase_it->second->getPointer_input(n * step), + phrase_it->second->getPointer_output(n * step), + step); + else + temp_ts.getPhrase(phrase_it->first) + ->connect(phrase_it->second->getPointer(n * step), step); + } + if (temp_ts.empty()) continue; + SingleClassGMM tmpGMM(shared_parameters); + tmpGMM.parameters.gaussians.set(parameters.gaussians.get()); + tmpGMM.parameters.relative_regularization.set( + parameters.relative_regularization.get()); + tmpGMM.parameters.absolute_regularization.set( + parameters.absolute_regularization.get()); + tmpGMM.parameters.covariance_mode.set(parameters.covariance_mode.get()); + tmpGMM.train(&temp_ts); + for (unsigned int c = 0; c < parameters.gaussians.get(); c++) { + states[n].components[c].mean = tmpGMM.components[c].mean; + states[n].components[c].covariance = + tmpGMM.components[c].covariance; + states[n].updateInverseCovariances(); + } + } +} + +void xmm::SingleClassHMM::setErgodic() { + unsigned int numStates = parameters.states.get(); + + for (int i = 0; i < numStates; i++) { + prior[i] = 1 / (float)numStates; + for (int j = 0; j < numStates; j++) { + transition[i * numStates + j] = 1 / (float)numStates; + } + } +} + +void xmm::SingleClassHMM::setLeftRight() { + unsigned int numStates = parameters.states.get(); + + transition.assign(numStates * 2, 0.5); + transition[(numStates - 1) * 2] = 1.; + transition[(numStates - 1) * 2 + 1] = 0.; +} + +void xmm::SingleClassHMM::normalizeTransitions() { + unsigned int numStates = parameters.states.get(); + + double norm_transition; + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + double norm_prior(0.); + for (int i = 0; i < numStates; i++) { + norm_prior += prior[i]; + norm_transition = 0.; + for (int j = 0; j < numStates; j++) + norm_transition += transition[i * numStates + j]; + for (int j = 0; j < numStates; j++) + transition[i * numStates + j] /= norm_transition; + } + for (int i = 0; i < numStates; i++) prior[i] /= norm_prior; + } else { + for (int i = 0; i < numStates; i++) { + norm_transition = transition[i * 2] + transition[i * 2 + 1]; + transition[i * 2] /= norm_transition; + transition[i * 2 + 1] /= norm_transition; + } + } +} + +#pragma mark - +#pragma mark Forward-Backward algorithm +double xmm::SingleClassHMM::forward_init(const float* observation, + const float* observation_output) { + unsigned int numStates = parameters.states.get(); + + double norm_const(0.); + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int i = 0; i < numStates; i++) { + if (shared_parameters->bimodal.get()) { + if (observation_output) + alpha[i] = prior[i] * + states[i].obsProb_bimodal(observation, + observation_output); + else + alpha[i] = prior[i] * states[i].obsProb_input(observation); + } else { + alpha[i] = prior[i] * states[i].obsProb(observation); + } + norm_const += alpha[i]; + } + } else { + alpha.assign(numStates, 0.0); + if (shared_parameters->bimodal.get()) { + if (observation_output) + alpha[0] = + states[0].obsProb_bimodal(observation, observation_output); + else + alpha[0] = states[0].obsProb_input(observation); + } else { + alpha[0] = states[0].obsProb(observation); + } + norm_const += alpha[0]; + } + if (norm_const > 0) { + for (int i = 0; i < numStates; i++) { + alpha[i] /= norm_const; + } + return 1 / norm_const; + } else { + for (int j = 0; j < numStates; j++) { + alpha[j] = 1. / double(numStates); + } + return 1.; + } +} + +double xmm::SingleClassHMM::forward_update(const float* observation, + const float* observation_output) { + unsigned int numStates = parameters.states.get(); + + double norm_const(0.); + previous_alpha_ = alpha; + for (int j = 0; j < numStates; j++) { + alpha[j] = 0.; + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int i = 0; i < numStates; i++) { + alpha[j] += previous_alpha_[i] * transition[i * numStates + j]; + } + } else { + alpha[j] += previous_alpha_[j] * transition[j * 2]; + if (j > 0) { + alpha[j] += + previous_alpha_[j - 1] * transition[(j - 1) * 2 + 1]; + } else { + alpha[0] += previous_alpha_[numStates - 1] * + transition[numStates * 2 - 1]; + } + } + if (shared_parameters->bimodal.get()) { + if (observation_output) + alpha[j] *= + states[j].obsProb_bimodal(observation, observation_output); + else + alpha[j] *= states[j].obsProb_input(observation); + } else { + alpha[j] *= states[j].obsProb(observation); + } + norm_const += alpha[j]; + } + if (norm_const > 1e-300) { + for (int j = 0; j < numStates; j++) { + alpha[j] /= norm_const; + } + return 1. / norm_const; + } else { + return 0.; + } +} + +void xmm::SingleClassHMM::backward_init(double ct) { + for (int i = 0; i < parameters.states.get(); i++) beta_[i] = ct; +} + +void xmm::SingleClassHMM::backward_update(double ct, const float* observation, + const float* observation_output) { + unsigned int numStates = parameters.states.get(); + + previous_beta_ = beta_; + for (int i = 0; i < numStates; i++) { + beta_[i] = 0.; + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int j = 0; j < numStates; j++) { + if (shared_parameters->bimodal.get()) { + if (observation_output) + beta_[i] += transition[i * numStates + j] * + previous_beta_[j] * + states[j].obsProb_bimodal( + observation, observation_output); + else + beta_[i] += transition[i * numStates + j] * + previous_beta_[j] * + states[j].obsProb_input(observation); + } else { + beta_[i] += transition[i * numStates + j] * + previous_beta_[j] * + states[j].obsProb(observation); + } + } + } else { + if (shared_parameters->bimodal.get()) { + if (observation_output) + beta_[i] += transition[i * 2] * previous_beta_[i] * + states[i].obsProb_bimodal(observation, + observation_output); + else + beta_[i] += transition[i * 2] * previous_beta_[i] * + states[i].obsProb_input(observation); + } else { + beta_[i] += transition[i * 2] * previous_beta_[i] * + states[i].obsProb(observation); + } + if (i < numStates - 1) { + if (shared_parameters->bimodal.get()) { + if (observation_output) + beta_[i] += transition[i * 2 + 1] * + previous_beta_[i + 1] * + states[i + 1].obsProb_bimodal( + observation, observation_output); + else + beta_[i] += transition[i * 2 + 1] * + previous_beta_[i + 1] * + states[i + 1].obsProb_input(observation); + } else { + beta_[i] += transition[i * 2 + 1] * previous_beta_[i + 1] * + states[i + 1].obsProb(observation); + } + } + } + beta_[i] *= ct; + if (std::isnan(beta_[i]) || std::isinf(fabs(beta_[i]))) { + beta_[i] = 1e100; + } + } +} + +#pragma mark - +#pragma mark Training algorithm +void xmm::SingleClassHMM::emAlgorithmInit(TrainingSet* trainingSet) { + if (!trainingSet || trainingSet->empty()) return; + unsigned int numStates = parameters.states.get(); + unsigned int numGaussians = parameters.gaussians.get(); + + initParametersToDefault(trainingSet->standardDeviation()); + + if (numGaussians > 0) { // TODO: weird > 0 + initMeansCovariancesWithGMMEM(trainingSet); + } else { + initMeansWithAllPhrases(trainingSet); + initCovariances_fullyObserved(trainingSet); + } + + unsigned int nbPhrases = trainingSet->size(); + + // Initialize Algorithm variables + // --------------------------------------- + gamma_sequence_.resize(nbPhrases); + epsilon_sequence_.resize(nbPhrases); + gamma_sequence_per_mixture_.resize(nbPhrases); + unsigned int maxT(0); + unsigned int i(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); ++it) { + unsigned int T = it->second->size(); + gamma_sequence_[i].resize(T * numStates); + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + epsilon_sequence_[i].resize(T * numStates * numStates); + } else { + epsilon_sequence_[i].resize(T * 2 * numStates); + } + gamma_sequence_per_mixture_[i].resize(numGaussians); + for (int c = 0; c < numGaussians; c++) { + gamma_sequence_per_mixture_[i][c].resize(T * numStates); + } + if (T > maxT) { + maxT = T; + } + i++; + } + alpha_seq_.resize(maxT * numStates); + beta_seq_.resize(maxT * numStates); + + gamma_sum_.resize(numStates); + gamma_sum_per_mixture_.resize(numStates * numGaussians); +} + +void xmm::SingleClassHMM::emAlgorithmTerminate() { + normalizeTransitions(); + gamma_sequence_.clear(); + epsilon_sequence_.clear(); + gamma_sequence_per_mixture_.clear(); + alpha_seq_.clear(); + beta_seq_.clear(); + gamma_sum_.clear(); + gamma_sum_per_mixture_.clear(); + SingleClassProbabilisticModel::emAlgorithmTerminate(); +} + +double xmm::SingleClassHMM::emAlgorithmUpdate(TrainingSet* trainingSet) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + unsigned int numStates = parameters.states.get(); + + double log_prob(0.); + + // Forward-backward for each phrase + // ================================================= + int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); ++it) { + if (it->second->size() > 0) + log_prob += baumWelch_forwardBackward(it->second, phraseIndex); + phraseIndex++; + } + + baumWelch_gammaSum(trainingSet); + + // Re-estimate model parameters + // ================================================= + + // set covariance and mixture coefficients to zero for each state + for (int i = 0; i < numStates; i++) { + for (int c = 0; c < parameters.gaussians.get(); c++) { + states[i].mixture_coeffs[c] = 0.; + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + states[i].components[c].covariance.assign(dimension * dimension, + 0.0); + } else { + states[i].components[c].covariance.assign(dimension, 0.0); + } + } + } + + baumWelch_estimateMixtureCoefficients(trainingSet); + baumWelch_estimateMeans(trainingSet); + baumWelch_estimateCovariances(trainingSet); + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) + baumWelch_estimatePrior(trainingSet); + baumWelch_estimateTransitions(trainingSet); + + return log_prob; +} + +double xmm::SingleClassHMM::baumWelch_forward_update( + std::vector<double>::iterator observation_likelihoods) { + unsigned int numStates = parameters.states.get(); + + double norm_const(0.); + previous_alpha_ = alpha; + for (int j = 0; j < numStates; j++) { + alpha[j] = 0.; + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int i = 0; i < numStates; i++) { + alpha[j] += previous_alpha_[i] * transition[i * numStates + j]; + } + } else { + alpha[j] += previous_alpha_[j] * transition[j * 2]; + if (j > 0) { + alpha[j] += + previous_alpha_[j - 1] * transition[(j - 1) * 2 + 1]; + } else { + alpha[0] += previous_alpha_[numStates - 1] * + transition[numStates * 2 - 1]; + } + } + alpha[j] *= observation_likelihoods[j]; + norm_const += alpha[j]; + } + if (norm_const > 1e-300) { + for (int j = 0; j < numStates; j++) { + alpha[j] /= norm_const; + } + return 1. / norm_const; + } else { + return 0.; + } +} + +void xmm::SingleClassHMM::baumWelch_backward_update( + double ct, std::vector<double>::iterator observation_likelihoods) { + unsigned int numStates = parameters.states.get(); + + previous_beta_ = beta_; + for (int i = 0; i < numStates; i++) { + beta_[i] = 0.; + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int j = 0; j < numStates; j++) { + beta_[i] += transition[i * numStates + j] * previous_beta_[j] * + observation_likelihoods[j]; + } + } else { + beta_[i] += transition[i * 2] * previous_beta_[i] * + observation_likelihoods[i]; + if (i < numStates - 1) { + beta_[i] += transition[i * 2 + 1] * previous_beta_[i + 1] * + observation_likelihoods[i + 1]; + } + } + beta_[i] *= ct; + if (std::isnan(beta_[i]) || std::isinf(fabs(beta_[i]))) { + beta_[i] = 1e100; + } + } +} + +double xmm::SingleClassHMM::baumWelch_forwardBackward( + std::shared_ptr<Phrase> currentPhrase, int phraseIndex) { + unsigned int T = currentPhrase->size(); + unsigned int numStates = parameters.states.get(); + + std::vector<double> ct(T); + std::vector<double>::iterator alpha_seq_it = alpha_seq_.begin(); + + double log_prob; + + std::vector<double> observation_probabilities(numStates * T); + for (unsigned int t = 0; t < T; ++t) { + for (unsigned int i = 0; i < numStates; i++) { + if (shared_parameters->bimodal.get()) { + observation_probabilities[t * numStates + i] = + states[i].obsProb_bimodal( + currentPhrase->getPointer_input(t), + currentPhrase->getPointer_output(t)); + } else { + observation_probabilities[t * numStates + i] = + states[i].obsProb(currentPhrase->getPointer(t)); + } + } + } + + // Forward algorithm + if (shared_parameters->bimodal.get()) { + ct[0] = forward_init(currentPhrase->getPointer_input(0), + currentPhrase->getPointer_output(0)); + } else { + ct[0] = forward_init(currentPhrase->getPointer(0)); + } + log_prob = -log(ct[0]); + copy(alpha.begin(), alpha.end(), alpha_seq_it); + alpha_seq_it += numStates; + + for (int t = 1; t < T; t++) { + ct[t] = baumWelch_forward_update(observation_probabilities.begin() + + t * numStates); + log_prob -= log(ct[t]); + copy(alpha.begin(), alpha.end(), alpha_seq_it); + alpha_seq_it += numStates; + } + + // Backward algorithm + backward_init(ct[T - 1]); + copy(beta_.begin(), beta_.end(), beta_seq_.begin() + (T - 1) * numStates); + + for (int t = int(T - 2); t >= 0; t--) { + baumWelch_backward_update( + ct[t], observation_probabilities.begin() + (t + 1) * numStates); + copy(beta_.begin(), beta_.end(), beta_seq_.begin() + t * numStates); + } + + // Compute Gamma Variable + for (int t = 0; t < T; t++) { + for (int i = 0; i < numStates; i++) { + gamma_sequence_[phraseIndex][t * numStates + i] = + alpha_seq_[t * numStates + i] * beta_seq_[t * numStates + i] / + ct[t]; + } + } + + // Compute Gamma variable for each mixture component + double oo; + double norm_const; + + for (int t = 0; t < T; t++) { + for (int i = 0; i < numStates; i++) { + norm_const = 0.; + if (parameters.gaussians.get() == 1) { + oo = observation_probabilities[t * numStates + i]; + gamma_sequence_per_mixture_[phraseIndex][0][t * numStates + i] = + gamma_sequence_[phraseIndex][t * numStates + i] * oo; + norm_const += oo; + } else { + for (int c = 0; c < parameters.gaussians.get(); c++) { + if (shared_parameters->bimodal.get()) { + oo = states[i].obsProb_bimodal( + currentPhrase->getPointer_input(t), + currentPhrase->getPointer_output(t), c); + } else { + oo = states[i].obsProb(currentPhrase->getPointer(t), c); + } + gamma_sequence_per_mixture_[phraseIndex][c][t * numStates + + i] = + gamma_sequence_[phraseIndex][t * numStates + i] * oo; + norm_const += oo; + } + } + if (norm_const > 0) + for (int c = 0; c < parameters.gaussians.get(); c++) + gamma_sequence_per_mixture_[phraseIndex][c][t * numStates + + i] /= + norm_const; + } + } + + // Compute Epsilon Variable + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int t = 0; t < T - 1; t++) { + for (int i = 0; i < numStates; i++) { + for (int j = 0; j < numStates; j++) { + epsilon_sequence_[phraseIndex][t * numStates * numStates + + i * numStates + j] = + alpha_seq_[t * numStates + i] * + transition[i * numStates + j] * + beta_seq_[(t + 1) * numStates + j]; + epsilon_sequence_[phraseIndex][t * numStates * numStates + + i * numStates + j] *= + observation_probabilities[(t + 1) * numStates + j]; + } + } + } + } else { + for (int t = 0; t < T - 1; t++) { + for (int i = 0; i < numStates; i++) { + epsilon_sequence_[phraseIndex][t * 2 * numStates + i * 2] = + alpha_seq_[t * numStates + i] * transition[i * 2] * + beta_seq_[(t + 1) * numStates + i]; + epsilon_sequence_[phraseIndex][t * 2 * numStates + i * 2] *= + observation_probabilities[(t + 1) * numStates + i]; + if (i < numStates - 1) { + epsilon_sequence_[phraseIndex][t * 2 * numStates + i * 2 + + 1] = + alpha_seq_[t * numStates + i] * transition[i * 2 + 1] * + beta_seq_[(t + 1) * numStates + i + 1]; + epsilon_sequence_[phraseIndex][t * 2 * numStates + i * 2 + + 1] *= + observation_probabilities[(t + 1) * numStates + i + 1]; + } + } + } + } + + return log_prob; +} + +void xmm::SingleClassHMM::baumWelch_gammaSum(TrainingSet* trainingSet) { + unsigned int numStates = parameters.states.get(); + unsigned int numGaussians = parameters.gaussians.get(); + + for (int i = 0; i < numStates; i++) { + gamma_sum_[i] = 0.; + for (int c = 0; c < numGaussians; c++) { + gamma_sum_per_mixture_[i * numGaussians + c] = 0.; + } + } + + unsigned int phraseLength; + unsigned int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); ++it) { + phraseLength = it->second->size(); + for (int i = 0; i < numStates; i++) { + for (int t = 0; t < phraseLength; t++) { + gamma_sum_[i] += + gamma_sequence_[phraseIndex][t * numStates + i]; + for (int c = 0; c < numGaussians; c++) { + gamma_sum_per_mixture_[i * numGaussians + c] += + gamma_sequence_per_mixture_[phraseIndex][c] + [t * numStates + i]; + } + } + } + phraseIndex++; + } +} + +void xmm::SingleClassHMM::baumWelch_estimateMixtureCoefficients( + TrainingSet* trainingSet) { + unsigned int numStates = parameters.states.get(); + + unsigned int phraseLength; + unsigned int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); ++it) { + phraseLength = it->second->size(); + for (int i = 0; i < numStates; i++) { + for (int t = 0; t < phraseLength; t++) { + for (int c = 0; c < parameters.gaussians.get(); c++) { + states[i].mixture_coeffs[c] += gamma_sequence_per_mixture_ + [phraseIndex][c][t * numStates + i]; + } + } + } + phraseIndex++; + } + + // Scale mixture coefficients + for (int i = 0; i < numStates; i++) { + states[i].normalizeMixtureCoeffs(); + } +} + +void xmm::SingleClassHMM::baumWelch_estimateMeans(TrainingSet* trainingSet) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + unsigned int numStates = parameters.states.get(); + unsigned int numGaussians = parameters.gaussians.get(); + + unsigned int phraseLength; + + for (int i = 0; i < numStates; i++) { + for (int c = 0; c < numGaussians; c++) { + states[i].components[c].mean.assign(dimension, 0.0); + } + } + + // Re-estimate Mean + int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); it++) { + phraseLength = it->second->size(); + for (int i = 0; i < numStates; i++) { + for (int t = 0; t < phraseLength; t++) { + for (int c = 0; c < numGaussians; c++) { + for (int d = 0; d < dimension; d++) { + states[i].components[c].mean[d] += + gamma_sequence_per_mixture_[phraseIndex][c] + [t * numStates + i] * + it->second->getValue(t, d); + } + } + } + } + phraseIndex++; + } + + // Normalize mean + for (int i = 0; i < numStates; i++) { + for (int c = 0; c < numGaussians; c++) { + for (int d = 0; d < dimension; d++) { + if (gamma_sum_per_mixture_[i * numGaussians + c] > 0) { + states[i].components[c].mean[d] /= + gamma_sum_per_mixture_[i * numGaussians + c]; + } + if (std::isnan(states[i].components[c].mean[d])) + throw std::runtime_error("Convergence Error"); + } + } + } +} + +void xmm::SingleClassHMM::baumWelch_estimateCovariances( + TrainingSet* trainingSet) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + unsigned int numStates = parameters.states.get(); + unsigned int numGaussians = parameters.gaussians.get(); + + unsigned int phraseLength; + + int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); it++) { + phraseLength = it->second->size(); + for (int i = 0; i < numStates; i++) { + for (int t = 0; t < phraseLength; t++) { + for (int c = 0; c < numGaussians; c++) { + for (int d1 = 0; d1 < dimension; d1++) { + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = d1; d2 < dimension; d2++) { + states[i] + .components[c] + .covariance[d1 * dimension + d2] += + gamma_sequence_per_mixture_ + [phraseIndex][c][t * numStates + i] * + (it->second->getValue(t, d1) - + states[i].components[c].mean[d1]) * + (it->second->getValue(t, d2) - + states[i].components[c].mean[d2]); + } + } else { + float value = it->second->getValue(t, d1) - + states[i].components[c].mean[d1]; + states[i].components[c].covariance[d1] += + gamma_sequence_per_mixture_[phraseIndex][c] + [t * numStates + i] * + value * value; + } + } + } + } + } + phraseIndex++; + } + + // Scale covariance + for (int i = 0; i < numStates; i++) { + for (int c = 0; c < numGaussians; c++) { + if (gamma_sum_per_mixture_[i * numGaussians + c] > 0) { + for (int d1 = 0; d1 < dimension; d1++) { + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = d1; d2 < dimension; d2++) { + states[i].components[c].covariance[d1 * dimension + + d2] /= + gamma_sum_per_mixture_[i * numGaussians + c]; + if (d1 != d2) + states[i] + .components[c] + .covariance[d2 * dimension + d1] = + states[i] + .components[c] + .covariance[d1 * dimension + d2]; + } + } else { + states[i].components[c].covariance[d1] /= + gamma_sum_per_mixture_[i * numGaussians + c]; + } + } + } + } + states[i].addCovarianceOffset(); + states[i].updateInverseCovariances(); + } +} + +void xmm::SingleClassHMM::baumWelch_estimatePrior(TrainingSet* trainingSet) { + unsigned int numStates = parameters.states.get(); + + // Set prior vector to 0 + for (int i = 0; i < numStates; i++) prior[i] = 0.; + + // Re-estimate Prior probabilities + double sumprior = 0.; + int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); it++) { + for (int i = 0; i < numStates; i++) { + prior[i] += gamma_sequence_[phraseIndex][i]; + sumprior += gamma_sequence_[phraseIndex][i]; + } + phraseIndex++; + } + + // Scale Prior vector + if (sumprior > 0.) { + for (int i = 0; i < numStates; i++) { + prior[i] /= sumprior; + } + } +} + +void xmm::SingleClassHMM::baumWelch_estimateTransitions( + TrainingSet* trainingSet) { + unsigned int numStates = parameters.states.get(); + + // Set prior vector and transition matrix to 0 + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + transition.assign(numStates * numStates, 0.0); + } else { + transition.assign(numStates * 2, 0.0); + } + + unsigned int phraseLength; + // Re-estimate Prior and Transition probabilities + unsigned int phraseIndex(0); + for (auto it = trainingSet->cbegin(); it != trainingSet->cend(); it++) { + phraseLength = it->second->size(); + if (phraseLength > 0) { + for (int i = 0; i < numStates; i++) { + // Experimental: A bit of regularization (sometimes avoids + // numerical + // errors) + if (parameters.transition_mode.get() == + HMM::TransitionMode::LeftRight) { + transition[i * 2] += TRANSITION_REGULARIZATION(); + if (i < numStates - 1) + transition[i * 2 + 1] += TRANSITION_REGULARIZATION(); + else + transition[i * 2] += TRANSITION_REGULARIZATION(); + } + // End Regularization + if (parameters.transition_mode.get() == + HMM::TransitionMode::Ergodic) { + for (int j = 0; j < numStates; j++) { + for (int t = 0; t < phraseLength - 1; t++) { + transition[i * numStates + j] += + epsilon_sequence_[phraseIndex][t * numStates * + numStates + + i * numStates + + j]; + } + } + } else { + for (int t = 0; t < phraseLength - 1; t++) { + transition[i * 2] += + epsilon_sequence_[phraseIndex][t * 2 * numStates + + i * 2]; + } + if (i < numStates - 1) { + for (int t = 0; t < phraseLength - 1; t++) { + transition[i * 2 + 1] += + epsilon_sequence_[phraseIndex][t * 2 * + numStates + + i * 2 + 1]; + } + } + } + } + } + phraseIndex++; + } + + // Scale transition matrix + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + for (int i = 0; i < numStates; i++) { + for (int j = 0; j < numStates; j++) { + transition[i * numStates + j] /= + (gamma_sum_[i] + 2. * TRANSITION_REGULARIZATION()); + if (std::isnan(transition[i * numStates + j])) + throw std::runtime_error( + "Convergence Error. Check your training data or " + "increase the variance offset"); + } + } + } else { + for (int i = 0; i < numStates; i++) { + transition[i * 2] /= + (gamma_sum_[i] + 2. * TRANSITION_REGULARIZATION()); + if (std::isnan(transition[i * 2])) + throw std::runtime_error( + "Convergence Error. Check your training data or increase " + "the variance offset"); + if (i < numStates - 1) { + transition[i * 2 + 1] /= + (gamma_sum_[i] + 2. * TRANSITION_REGULARIZATION()); + if (std::isnan(transition[i * 2 + 1])) + throw std::runtime_error( + "Convergence Error. Check your training data or " + "increase the variance offset"); + } + } + } +} + +#pragma mark - +#pragma mark Performance + +void xmm::SingleClassHMM::reset() { + check_training(); + SingleClassProbabilisticModel::reset(); + forward_initialized_ = false; + if (is_hierarchical_) { + for (int i = 0; i < 3; i++) + alpha_h[i].resize(parameters.states.get(), 0.0); + alpha.clear(); + previous_alpha_.clear(); + beta_.clear(); + previous_beta_.clear(); + } else { + addCyclicTransition(0.05); + } +} + +void xmm::SingleClassHMM::addCyclicTransition(double proba) { + unsigned int numStates = parameters.states.get(); + + check_training(); + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) { + if (numStates > 1) transition[(numStates - 1) * numStates] = proba; + } else { + if (numStates > 1) transition[(numStates - 1) * 2 + 1] = proba; + } +} + +double xmm::SingleClassHMM::filter(std::vector<float> const& observation) { + check_training(); + double ct; + + if (forward_initialized_) { + ct = forward_update(&observation[0]); + } else { + this->likelihood_buffer_.clear(); + ct = forward_init(&observation[0]); + } + + forward_initialized_ = true; + + results.instant_likelihood = 1. / ct; + updateAlphaWindow(); + updateResults(); + + if (shared_parameters->bimodal.get()) { + regression(observation); + } + + return results.instant_likelihood; +} + +unsigned int argmax(std::vector<double> const& v) { + unsigned int amax(-1); + if (v.size() == 0) return amax; + double current_max(v[0]); + for (unsigned int i = 1; i < v.size(); ++i) { + if (v[i] > current_max) { + current_max = v[i]; + amax = i; + } + } + return amax; +} + +void xmm::SingleClassHMM::updateAlphaWindow() { + unsigned int numStates = parameters.states.get(); + + check_training(); + results.likeliest_state = 0; + // Get likeliest State + double best_alpha(is_hierarchical_ ? (alpha_h[0][0] + alpha_h[1][0]) + : alpha[0]); + for (unsigned int i = 1; i < numStates; ++i) { + if (is_hierarchical_) { + if ((alpha_h[0][i] + alpha_h[1][i]) > best_alpha) { + best_alpha = alpha_h[0][i] + alpha_h[1][i]; + results.likeliest_state = i; + } + } else { + if (alpha[i] > best_alpha) { + best_alpha = alpha[i]; + results.likeliest_state = i; + } + } + } + + // Compute Window + window_minindex_ = (static_cast<int>(results.likeliest_state) - + static_cast<int>(numStates) / 2); + window_maxindex_ = (static_cast<int>(results.likeliest_state) + + static_cast<int>(numStates) / 2); + window_minindex_ = (window_minindex_ >= 0) ? window_minindex_ : 0; + window_maxindex_ = (window_maxindex_ <= static_cast<int>(numStates)) + ? window_maxindex_ + : static_cast<int>(numStates); + window_normalization_constant_ = 0.0; + for (int i = window_minindex_; i < window_maxindex_; ++i) { + window_normalization_constant_ += + is_hierarchical_ ? (alpha_h[0][i] + alpha_h[1][i]) : alpha[i]; + } +} + +void xmm::SingleClassHMM::regression( + std::vector<float> const& observation_input) { + check_training(); + unsigned int dimension_output = shared_parameters->dimension.get() - + shared_parameters->dimension_input.get(); + results.output_values.assign(dimension_output, 0.0); + results.output_covariance.assign( + (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) + ? dimension_output * dimension_output + : dimension_output, + 0.0); + std::vector<float> tmp_predicted_output(dimension_output); + + if (parameters.regression_estimator.get() == + HMM::RegressionEstimator::Likeliest) { + states[results.likeliest_state].likelihood(observation_input); + states[results.likeliest_state].regression(observation_input); + results.output_values = + states[results.likeliest_state].results.output_values; + return; + } + + unsigned int clip_min_state = (parameters.regression_estimator.get() == + HMM::RegressionEstimator::Full) + ? 0 + : window_minindex_; + unsigned int clip_max_state = (parameters.regression_estimator.get() == + HMM::RegressionEstimator::Full) + ? parameters.states.get() + : window_maxindex_; + double normalization_constant = (parameters.regression_estimator.get() == + HMM::RegressionEstimator::Full) + ? 1.0 + : window_normalization_constant_; + + if (normalization_constant <= 0.0) normalization_constant = 1.; + + // Compute Regression + for (unsigned int i = clip_min_state; i < clip_max_state; ++i) { + states[i].likelihood(observation_input); + states[i].regression(observation_input); + tmp_predicted_output = states[i].results.output_values; + for (unsigned int d = 0; d < dimension_output; ++d) { + if (is_hierarchical_) { + results.output_values[d] += (alpha_h[0][i] + alpha_h[1][i]) * + tmp_predicted_output[d] / + normalization_constant; + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension_output; ++d2) + results.output_covariance[d * dimension_output + d2] += + (alpha_h[0][i] + alpha_h[1][i]) * + (alpha_h[0][i] + alpha_h[1][i]) * + states[i] + .results + .output_covariance[d * dimension_output + d2] / + normalization_constant; + } else { + results.output_covariance[d] += + (alpha_h[0][i] + alpha_h[1][i]) * + (alpha_h[0][i] + alpha_h[1][i]) * + states[i].results.output_covariance[d] / + normalization_constant; + } + } else { + results.output_values[d] += + alpha[i] * tmp_predicted_output[d] / normalization_constant; + if (parameters.covariance_mode.get() == + GaussianDistribution::CovarianceMode::Full) { + for (int d2 = 0; d2 < dimension_output; ++d2) + results.output_covariance[d * dimension_output + d2] += + alpha[i] * alpha[i] * + states[i] + .results + .output_covariance[d * dimension_output + d2] / + normalization_constant; + + } else { + results.output_covariance[d] += + alpha[i] * alpha[i] * + states[i].results.output_covariance[d] / + normalization_constant; + } + } + } + } +} + +void xmm::SingleClassHMM::updateResults() { + likelihood_buffer_.push(log(results.instant_likelihood)); + results.log_likelihood = 0.0; + unsigned int bufSize = likelihood_buffer_.size_t(); + for (unsigned int i = 0; i < bufSize; i++) { + results.log_likelihood += likelihood_buffer_(0, i); + } + results.log_likelihood /= double(bufSize); + + results.progress = 0.0; + for (int i = window_minindex_; i < window_maxindex_; ++i) { + if (is_hierarchical_) + results.progress += + (alpha_h[0][i] + alpha_h[1][i] + alpha_h[2][i]) * i / + window_normalization_constant_; + else + results.progress += alpha[i] * i / window_normalization_constant_; + } + results.progress /= double(parameters.states.get() - 1); + + // ///////////////////////// + // results_progress = 0.0; + // for (unsigned int i=0 ; i<numStates; i++) { + // if (is_hierarchical_) + // results_progress += (alpha_h[0][i] + alpha_h[1][i] + + // alpha_h[2][i]) * i; + // else + // results_progress += alpha[i] * i; + // } + // results_progress /= double(numStates-1); + // ///////////////////////// +} + +#pragma mark - +#pragma mark File IO +Json::Value xmm::SingleClassHMM::toJson() const { + check_training(); + Json::Value root = SingleClassProbabilisticModel::toJson(); + root["parameters"] = parameters.toJson(); + if (parameters.transition_mode.get() == HMM::TransitionMode::Ergodic) + root["prior"] = vector2json(prior); + root["transition"] = vector2json(transition); + root["exitProbabilities"] = vector2json(exit_probabilities_); + + root["states"].resize( + static_cast<Json::ArrayIndex>(parameters.states.get())); + for (int s = 0; s < parameters.states.get(); s++) { + root["states"][s] = states[s].toJson(); + } + return root; +} + +void xmm::SingleClassHMM::fromJson(Json::Value const& root) { + check_training(); + try { + SingleClassHMM tmp(shared_parameters, root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +#pragma mark - +#pragma mark Exit Probabilities + +void xmm::SingleClassHMM::updateExitProbabilities(float* exitProbabilities) { + unsigned int numStates = parameters.states.get(); + + if (!is_hierarchical_) + throw std::runtime_error( + "Model is Not hierarchical: method cannot be used"); + if (exitProbabilities == NULL) { + exit_probabilities_.resize(numStates, 0.0); + exit_probabilities_[numStates - 1] = + DEFAULT_EXITPROBABILITY_LAST_STATE(); + } else { + exit_probabilities_.resize(numStates, 0.0); + for (int i = 0; i < numStates; i++) try { + exit_probabilities_[i] = exitProbabilities[i]; + } catch (std::exception& e) { + throw std::invalid_argument( + "Wrong format for exit probabilities"); + } + } +} + +void xmm::SingleClassHMM::addExitPoint(int stateIndex, float proba) { + if (!is_hierarchical_) + throw std::runtime_error( + "Model is Not hierarchical: method cannot be used"); + if (stateIndex >= parameters.states.get()) + throw std::out_of_range("State index out of bounds"); + exit_probabilities_[stateIndex] = proba; +} + +//#pragma mark > Conversion & Extraction +// void xmm::SingleClassHMM::makeBimodal(unsigned int dimension_input) +//{ +// check_training(); +// if (bimodal_) +// throw std::runtime_error("The model is already bimodal"); +// if (dimension_input >= dimension_) +// throw std::out_of_range("Request input dimension exceeds the current +// dimension"); +// flags_ = flags_ | BIMODAL; +// bimodal_ = true; +// dimension_input_ = dimension_input; +// for (unsigned int i=0; i<numStates; i++) { +// states[i].makeBimodal(dimension_input); +// } +// results_predicted_output.resize(dimension_ - dimension_input_); +// results_output_variance.resize(dimension_ - dimension_input_); +//} +// +// void xmm::SingleClassHMM::makeUnimodal() +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model is already unimodal"); +// flags_ = NONE; +// bimodal_ = false; +// dimension_input_ = 0; +// for (unsigned int i=0; i<numStates; i++) { +// states[i].makeUnimodal(); +// } +// results_predicted_output.clear(); +// results_output_variance.clear(); +//} +// +// xmm::HMM xmm::SingleClassHMM::extractSubmodel(std::vector<unsigned int>& +// columns) const +//{ +// check_training(); +// if (columns.size() > dimension_) +// throw std::out_of_range("requested number of columns exceeds the +// dimension of the current model"); +// for (unsigned int column=0; column<columns.size(); ++column) { +// if (columns[column] >= dimension_) +// throw std::out_of_range("Some column indices exceeds the dimension +// of the current model"); +// } +// HMM target_model(*this); +// size_t new_dim = columns.size(); +// target_model.setTrainingCallback(NULL, NULL); +// target_model.bimodal_ = false; +// target_model.dimension_ = static_cast<unsigned int>(new_dim); +// target_model.dimension_input_ = 0; +// target_model.flags_ = (this->flags_ & HIERARCHICAL); +// target_model.allocate(); +// for (unsigned int i=0; i<numStates; ++i) { +// target_model.states[i] = states[i].extractSubmodel(columns); +// } +// return target_model; +//} +// +// xmm::HMM xmm::SingleClassHMM::extractSubmodel_input() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_input(dimension_input_); +// for (unsigned int i=0; i<dimension_input_; ++i) { +// columns_input[i] = i; +// } +// return extractSubmodel(columns_input); +//} +// +// xmm::HMM xmm::SingleClassHMM::extractSubmodel_output() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns_output(dimension_ - dimension_input_); +// for (unsigned int i=dimension_input_; i<dimension_; ++i) { +// columns_output[i-dimension_input_] = i; +// } +// return extractSubmodel(columns_output); +//} +// +// xmm::HMM xmm::SingleClassHMM::extract_inverse_model() const +//{ +// check_training(); +// if (!bimodal_) +// throw std::runtime_error("The model needs to be bimodal"); +// std::vector<unsigned int> columns(dimension_); +// for (unsigned int i=0; i<dimension_-dimension_input_; ++i) { +// columns[i] = i+dimension_input_; +// } +// for (unsigned int i=dimension_-dimension_input_, j=0; i<dimension_; ++i, +// ++j) { +// columns[i] = j; +// } +// HMM target_model = extractSubmodel(columns); +// target_model.makeBimodal(dimension_-dimension_input_); +// return target_model; +//} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmSingleClass.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmSingleClass.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7dd78f3b1a59a09a18a32598ac5554343df121ab --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/hmm/xmmHmmSingleClass.hpp @@ -0,0 +1,527 @@ +/* + * xmmHmmSingleClass.hpp + * + * Hidden Markov Model Definition for a Single Class + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmHmmSingleClass_hpp +#define xmmHmmSingleClass_hpp + +#include "../gmm/xmmGmmSingleClass.hpp" +#include "xmmHmmParameters.hpp" +#include "xmmHmmResults.hpp" + +namespace xmm { +/** @ingroup HMM + @brief Single-Class Hidden Markov Model + @details Hidden Markov Model with Multivariate Gaussian Mixture Model + Observation Distributions. + Supports Bimodal data and Hidden Markov Regression. Built for Hierarchical HMMs + */ +class SingleClassHMM : public SingleClassProbabilisticModel { + template <typename SingleClassModel, typename ModelType> + friend class Model; + friend class HierarchicalHMM; + + public: + static const float DEFAULT_EXITPROBABILITY_LAST_STATE() { return 0.1; } + static const float TRANSITION_REGULARIZATION() { return 1.0e-5; } + + /** + @brief Constructor + @param p Shared Parameters (owned by a multiclass object) + */ + SingleClassHMM(std::shared_ptr<SharedParameters> p = NULL); + + /** + @brief Copy constructor + @param src Source Model + */ + SingleClassHMM(SingleClassHMM const& src); + + /** + @brief Copy constructor + @param p pointer to a shared parameters object (owned by a Model) + @param root Json structure + */ + explicit SingleClassHMM(std::shared_ptr<SharedParameters> p, + Json::Value const& root); + + /** + @brief Assignment + @param src Source Model + */ + SingleClassHMM& operator=(SingleClassHMM const& src); + + /** @name Accessors */ + ///@{ + + /** + @brief Set the exit probability of a specific state + @details this method is only active in 'HIERARCHICAL' mode. The probability + @param stateIndex index of the state to add the exit point + @param proba probability to exit the gesture from this state + @throws runtime_error if the model is not hierarchical + @throws out_of_range if the state index is out of bounds + */ + void addExitPoint(int stateIndex, float proba); + + ///@} + + /** @name Performance */ + ///@{ + + /** + @brief Resets the fitering process (recognition or regression) + */ + void reset(); + + /** + @brief filters a incoming observation (performs recognition or regression) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + @return likelihood of the observation + */ + double filter(std::vector<float> const& observation); + + ///@} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + virtual Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root); + + ///@} + + // /** + // @brief Convert to bimodal HMM in place + // @param dimension_input dimension of the input modality + // @throws runtime_error if the model is already bimodal + // @throws out_of_range if the requested input dimension is too + // large + // */ + // void makeBimodal(unsigned int dimension_input); + // + // /** + // @brief Convert to unimodal HMM in place + // @throws runtime_error if the model is already unimodal + // */ + // void makeUnimodal(); + // + // /** + // @brief extract a submodel with the given columns + // @param columns columns indices in the target order + // @throws runtime_error if the model is training + // @throws out_of_range if the number or indices of the requested + // columns exceeds the current dimension + // @return a HMM from the current model considering only the target + // columns + // */ + // HMM extractSubmodel(std::vector<unsigned int>& columns) const; + // + // /** + // @brief extract the submodel of the input modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal HMM of the input modality from the current + // bimodal model + // */ + // HMM extractSubmodel_input() const; + // + // /** + // @brief extract the submodel of the output modality + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a unimodal HMM of the output modality from the current + // bimodal model + // */ + // HMM extractSubmodel_output() const; + // + // /** + // @brief extract the model with reversed input and output + // modalities + // @throws runtime_error if the model is training or if it is not + // bimodal + // @return a bimodal HMM that swaps the input and output modalities + // */ + // HMM extract_inverse_model() const; + + /** + @brief Model Parameters + */ + ClassParameters<HMM> parameters; + + /** + @brief Results of the filtering process (recognition & regression) + */ + ClassResults<HMM> results; + + /** + @brief State probabilities estimated by the forward algorithm. + */ + std::vector<double> alpha; + + /** + @brief State probabilities estimated by the hierarchical forward algorithm. + @details the variable is only allocated/used in hierarchical mode (see + 'HIERARCHICAL' flag) + */ + std::vector<double> alpha_h[3]; + + /** + @brief States of the model (Gaussian Mixture Models) + */ + std::vector<SingleClassGMM> states; + + /** + @brief Prior probabilities + */ + std::vector<float> prior; + + /** + @brief Transition Matrix + */ + std::vector<float> transition; + + protected: + /** + @brief Allocate model parameters + */ + void allocate(); + + /** + @brief initialize model parameters to their default values + */ + void initParametersToDefault(std::vector<float> const& dataStddev); + + /** + @brief initialize the means of each state with all training phrases (single + gaussian) + */ + void initMeansWithAllPhrases(TrainingSet* trainingSet); + + /** + @brief initialize the covariances of each state with all training phrases + (single gaussian) + */ + void initCovariances_fullyObserved(TrainingSet* trainingSet); + + /** + @brief initialize the means and covariances of each state using GMM-EM on + segments. + */ + void initMeansCovariancesWithGMMEM(TrainingSet* trainingSet); + + /** + @brief set the prior and transition matrix to ergodic + */ + void setErgodic(); + + /** + @brief set the prior and transition matrix to left-right (no state skip) + */ + void setLeftRight(); + + /** + @brief Normalize transition probabilities + */ + void normalizeTransitions(); + + /** + @brief Initialization of the forward algorithm + @param observation observation vector at time t. If the model is bimodal, + this vector + should be only the observation on the input modality. + @param observation_output observation on the output modality (only used if + the model is bimodal). + If unspecified, the update is performed on the input modality only. + @return instantaneous likelihood + */ + double forward_init(const float* observation, + const float* observation_output = NULL); + + /** + @brief Update of the forward algorithm + @param observation observation vector at time t. If the model is bimodal, + this vector + should be only the observation on the input modality. + @param observation_output observation on the output modality (only used if + the model is bimodal). + If unspecified, the update is performed on the input modality only. + @return instantaneous likelihood + */ + double forward_update(const float* observation, + const float* observation_output = NULL); + + /** + @brief Initialization Backward algorithm + @param ct inverse of the likelihood at time step t computed + with the forward algorithm (see Rabiner 1989) + */ + void backward_init(double ct); + + /** + @brief Update of the Backward algorithm + @param ct inverse of the likelihood at time step t computed + with the forward algorithm (see Rabiner 1989) + @param observation observation vector at time t. If the model is bimodal, + this vector + should be only the observation on the input modality. + @param observation_output observation on the output modality (only used if + the model is bimodal). + If unspecified, the update is performed on the input modality only. + */ + void backward_update(double ct, const float* observation, + const float* observation_output = NULL); + + /** + @brief Initialization of the parameters before training + */ + void emAlgorithmInit(TrainingSet* trainingSet); + + /** + @brief Termination of the training algorithm + */ + void emAlgorithmTerminate(); + + /** + @brief update method of the EM algorithm (calls Baum-Welch Algorithm) + */ + virtual double emAlgorithmUpdate(TrainingSet* trainingSet); + + /** + @brief Compute the forward-backward algorithm on a phrase of the training + set + @param currentPhrase pointer to the phrase of the training set + @param phraseIndex index of the phrase + @return lieklihood of the phrase given the model's current parameters + */ + double baumWelch_forwardBackward(std::shared_ptr<Phrase> currentPhrase, + int phraseIndex); + + /** + @brief Update of the forward algorithm for Training (observation + probabilities are pre-computed) + @param observation_likelihoods likelihoods of the observations for each + state + @return instantaneous likelihood + */ + double baumWelch_forward_update( + std::vector<double>::iterator observation_likelihoods); + + /** + @brief Update of the Backward algorithm for Training (observation + probabilities are pre-computed) + @param ct inverse of the likelihood at time step t computed + with the forward algorithm (see Rabiner 1989) + @param observation_likelihoods likelihoods of the observations for each + state + */ + void baumWelch_backward_update( + double ct, std::vector<double>::iterator observation_likelihoods); + + /** + @brief Compute the sum of the gamma variable (for use in EM) + */ + void baumWelch_gammaSum(TrainingSet* trainingSet); + + /** + @brief Estimate the Coefficients of the Gaussian Mixture for each state + */ + void baumWelch_estimateMixtureCoefficients(TrainingSet* trainingSet); + + /** + @brief Estimate the Means of the Gaussian Distribution for each state + */ + void baumWelch_estimateMeans(TrainingSet* trainingSet); + + /** + @brief Estimate the Covariances of the Gaussian Distribution for each state + */ + void baumWelch_estimateCovariances(TrainingSet* trainingSet); + + /** + @brief Estimate the Prior Probabilities + */ + void baumWelch_estimatePrior(TrainingSet* trainingSet); + + /** + @brief Estimate the Transition Probabilities + */ + void baumWelch_estimateTransitions(TrainingSet* trainingSet); + + /** + @brief Adds a cyclic Transition probability (from last state to first + state) + @details avoids getting stuck at the end of the model. this method is idle + for a hierarchical model. + @param proba probability of the transition form last to first state + */ + void addCyclicTransition(double proba); + + /** + @brief Estimates the likeliest state and compute the bounds of the windows + over the states. + @details The window is centered around the likeliest state, and its size is + the number of states. + The window is clipped to the first and last states. + */ + void updateAlphaWindow(); + + /** + @brief Compute the regression for the case of a bimodal model, given the + estimated state probabilities estimated by forward algorithm. + @details predicted output parameters are stored in the result structure. + @param observation_input observation on the input modality + */ + void regression(std::vector<float> const& observation_input); + + /** + @brief update the content of the likelihood buffer and return average + likelihood. + @details The method also updates the cumulative log-likelihood computed + over a window (cumulativeloglikelihood) + */ + void updateResults(); + + /** + @brief Update the exit probability vector given the probabilities + @details this method is only active in 'HIERARCHICAL' mode. The probability + vector defines the probability of exiting the gesture from each state. If + unspecified, + only the last state of the gesture has a non-zero probability. + @param _exitProbabilities vector of exit probabilities (size must be + nbStates) + @throws runtime_error if the model is not hierarchical + */ + void updateExitProbabilities(float* _exitProbabilities = NULL); + + protected: + /** + @brief Defines if the forward algorithm has been initialized + */ + bool forward_initialized_; + + /** + @brief used to store the alpha estimated at the previous time step + */ + std::vector<double> previous_alpha_; + + /** + @brief backward state probabilities + */ + std::vector<double> beta_; + + /** + @brief used to store the beta estimated at the previous time step + */ + std::vector<double> previous_beta_; + + /** + @brief Sequence of Gamma probabilities + */ + std::vector<std::vector<double> > gamma_sequence_; + + /** + @brief Sequence of Epsilon probabilities + */ + std::vector<std::vector<double> > epsilon_sequence_; + + /** + @brief Sequence of Gamma probabilities for each mixture component + */ + std::vector<std::vector<std::vector<double> > > gamma_sequence_per_mixture_; + + /** + @brief Sequence of alpha (forward) probabilities + */ + std::vector<double> alpha_seq_; + + /** + @brief Sequence of beta (backward) probabilities + */ + std::vector<double> beta_seq_; + + /** + @brief Used to store the sums of the gamma variable + */ + std::vector<double> gamma_sum_; + + /** + @brief Used to store the sums of the gamma variable for each mixture + component + */ + std::vector<double> gamma_sum_per_mixture_; + + /** + @brief Defines if the model is a submodel of a hierarchical HMM. + @details in practice this adds exit probabilities to each state. These + probabilities are set + to the last state by default. + */ + bool is_hierarchical_; + + /** + @brief Exit probabilities for a hierarchical model. + */ + std::vector<float> exit_probabilities_; + + /** + @brief minimum index of the alpha window (used for regression & time + progression) + */ + int window_minindex_; + + /** + @brief minimum index of the alpha window (used for regression & time + progression) + */ + int window_maxindex_; + + /** + @brief normalization constant of the alpha window (used for regression & + time progression) + */ + double window_normalization_constant_; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeans.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeans.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd04cd62cd801367567fabb133d939889e51bf55 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeans.cpp @@ -0,0 +1,284 @@ +/* + * xmmKMeans.hpp + * + * K-Means clustering + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmKMeans.hpp" +#include <limits> + +#ifdef WIN32 +static long random() { return rand(); } +#endif +#define kmax(a, b) (((a) > (b)) ? (a) : (b)) + +#pragma mark - +#pragma mark === Public Interface === +#pragma mark > Constructors +xmm::KMeans::KMeans(unsigned int clusters_) + : shared_parameters(std::make_shared<SharedParameters>()), + initialization_mode(InitializationMode::Random) { + configuration.clusters.set(clusters_); +} + +xmm::KMeans::KMeans(KMeans const& src) + : configuration(src.configuration), + centers(src.centers), + initialization_mode(src.initialization_mode) {} + +xmm::KMeans& xmm::KMeans::operator=(KMeans const& src) { + if (this != &src) { + initialization_mode = src.initialization_mode; + configuration = src.configuration; + centers = src.centers; + } + return *this; +} + +#pragma mark > Training +void xmm::KMeans::train(TrainingSet* trainingSet) { + if (!trainingSet || trainingSet->empty()) return; + + shared_parameters->dimension.set(trainingSet->dimension.get()); + centers.resize( + configuration.clusters.get() * shared_parameters->dimension.get(), 0.0); + if (initialization_mode == InitializationMode::Random) + randomizeClusters(trainingSet->standardDeviation()); + else + initClustersWithFirstPhrase(trainingSet->begin()->second); + + int dimension = static_cast<int>(shared_parameters->dimension.get()); + int clusters = static_cast<int>(configuration.clusters.get()); + + for (int trainingNbIterations = 0; + trainingNbIterations < configuration.max_iterations.get(); + ++trainingNbIterations) { + std::vector<float> previous_centers = centers; + + updateCenters(previous_centers, trainingSet); + + float meanClusterDistance(0.0); + float maxRelativeCenterVariation(0.0); + for (unsigned int k = 0; k < clusters; ++k) { + for (unsigned int l = 0; l < clusters; ++l) { + if (k != l) { + meanClusterDistance += + euclidean_distance(¢ers[k * dimension], + ¢ers[l * dimension], dimension); + } + } + maxRelativeCenterVariation = + kmax(euclidean_distance(&previous_centers[k * dimension], + ¢ers[k * dimension], dimension), + maxRelativeCenterVariation); + } + meanClusterDistance /= float(clusters * (clusters - 1)); + maxRelativeCenterVariation /= float(clusters); + maxRelativeCenterVariation /= meanClusterDistance; + if (maxRelativeCenterVariation < + configuration.relative_distance_threshold.get()) + break; + } +} + +void xmm::KMeans::initClustersWithFirstPhrase(std::shared_ptr<Phrase> phrase) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + unsigned int step = phrase->size() / configuration.clusters.get(); + + unsigned int offset(0); + for (unsigned int c = 0; c < configuration.clusters.get(); c++) { + for (unsigned int d = 0; d < dimension; d++) { + centers[c * dimension + d] = 0.0; + } + for (unsigned int t = 0; t < step; t++) { + for (unsigned int d = 0; d < dimension; d++) { + centers[c * dimension + d] += + phrase->getValue(offset + t, d) / float(step); + } + } + offset += step; + } +} + +void xmm::KMeans::randomizeClusters( + std::vector<float> const& trainingSetVariance) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + for (unsigned int k = 0; k < configuration.clusters.get(); ++k) { + for (unsigned int d = 0; d < dimension; ++d) { + centers[k * dimension + d] = + trainingSetVariance[d] * (2. * random() / float(RAND_MAX) - 1.); + } + } +} + +void xmm::KMeans::updateCenters(std::vector<float>& previous_centers, + TrainingSet* trainingSet) { + int dimension = static_cast<int>(shared_parameters->dimension.get()); + int clusters = static_cast<int>(configuration.clusters.get()); + + unsigned int phraseIndex(0); + centers.assign(clusters * dimension, 0.0); + std::vector<unsigned int> numFramesPerCluster(clusters, 0); + for (auto it = trainingSet->begin(); it != trainingSet->end(); + ++it, ++phraseIndex) { + for (unsigned int t = 0; t < it->second->size(); ++t) { + float min_distance; + if (trainingSet->bimodal()) { + std::vector<float> frame(dimension); + for (unsigned int d = 0; d < dimension; ++d) { + frame[d] = it->second->getValue(t, d); + } + min_distance = euclidean_distance( + &frame[0], &previous_centers[0], dimension); + } else { + min_distance = euclidean_distance( + it->second->getPointer(t), &previous_centers[0], dimension); + } + unsigned int cluster_membership(0); + for (unsigned int k = 1; k < clusters; ++k) { + float distance; + if (trainingSet->bimodal()) { + std::vector<float> frame(dimension); + for (unsigned int d = 0; d < dimension; ++d) { + frame[d] = it->second->getValue(t, d); + } + distance = euclidean_distance( + &frame[0], &previous_centers[k * dimension], dimension); + } else { + distance = euclidean_distance( + it->second->getPointer(t), + &previous_centers[k * dimension], dimension); + } + if (distance < min_distance) { + cluster_membership = k; + min_distance = distance; + } + } + numFramesPerCluster[cluster_membership]++; + for (unsigned int d = 0; d < dimension; ++d) { + centers[cluster_membership * dimension + d] += + it->second->getValue(t, d); + } + } + } + for (unsigned int k = 0; k < clusters; ++k) { + if (numFramesPerCluster[k] > 0) + for (unsigned int d = 0; d < dimension; ++d) { + centers[k * dimension + d] /= float(numFramesPerCluster[k]); + } + } +} + +#pragma mark > Performance +void xmm::KMeans::reset() { + results.distances.resize(configuration.clusters.get(), 0.0); +} + +void xmm::KMeans::filter(std::vector<float> const& observation) { + if (observation.size() != shared_parameters->dimension.get()) + throw std::runtime_error("Observation has wrong dimension"); + int dimension = static_cast<int>(shared_parameters->dimension.get()); + results.likeliest = 0; + float minDistance(std::numeric_limits<float>::max()); + for (unsigned int k = 0; k < configuration.clusters.get(); ++k) { + results.distances[k] = euclidean_distance( + &observation[0], ¢ers[k * dimension], dimension); + if (results.distances[k] < minDistance) { + minDistance = results.distances[k]; + results.likeliest = k; + } + } +} + +#pragma mark - +#pragma mark File IO +Json::Value xmm::KMeans::toJson() const { + // JSONNode json_model(JSON_NODE); + // json_model.set_name("KMeans"); + // + // json_model.push_back(JSONNode("dimension", dimension_)); + // json_model.push_back(JSONNode("nbclusters", nbClusters_)); + // json_model.push_back(vector2json(centers, "centers")); + + return Json::Value(); +} + +void xmm::KMeans::fromJson(Json::Value const& root) { + // try { + // if (root.type() != JSON_NODE) + // throw JSONException("Wrong type: was expecting 'JSON_NODE'", + // root.name()); + // JSONNode::const_iterator root_it = root.begin(); + // + // // Get Dimension + // root_it = root.find("dimension"); + // if (root_it == root.end()) + // throw JSONException("JSON Node is incomplete", + // root_it->name()); + // if (root_it->type() != JSON_NUMBER) + // throw JSONException("Wrong type for node 'dimension': was + // expecting 'JSON_NUMBER'", root_it->name()); + // dimension_ = static_cast<unsigned int>(root_it->as_int()); + // + // // Get Number of Clusters + // root_it = root.find("nbclusters"); + // if (root_it == root.end()) + // throw JSONException("JSON Node is incomplete", + // root_it->name()); + // if (root_it->type() != JSON_NUMBER) + // throw JSONException("Wrong type for node 'nbclusters': was + // expecting 'JSON_NUMBER'", root_it->name()); + // nbClusters_ = static_cast<unsigned int>(root_it->as_int()); + // + // // Get Cluster Centers + // root_it = root.find("centers"); + // if (root_it == root.end()) + // throw JSONException("JSON Node is incomplete", + // root_it->name()); + // if (root_it->type() != JSON_ARRAY) + // throw JSONException("Wrong type for node 'centers': was + // expecting 'JSON_ARRAY'", root_it->name()); + // json2vector(*root_it, centers, nbClusters_); + // } catch (JSONException &e) { + // throw JSONException(e, root.name()); + // } catch (std::exception &e) { + // throw JSONException(e, root.name()); + // } +} + +#pragma mark > Utility +template <typename T> +T xmm::euclidean_distance(const T* vector1, const T* vector2, + unsigned int dimension) { + T distance(0.0); + for (unsigned int d = 0; d < dimension; d++) { + distance += (vector1[d] - vector2[d]) * (vector1[d] - vector2[d]); + } + return sqrt(distance); +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeans.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeans.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a926f448f7e42a84c1c51d6cf9f28416a7d47278 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeans.hpp @@ -0,0 +1,179 @@ +/* + * xmmKMeans.hpp + * + * K-Means clustering + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmKMeans_h +#define xmmKMeans_h + +#include "../../core/model/xmmModelConfiguration.hpp" +#include "../../core/model/xmmModelSingleClass.hpp" +#include "xmmKMeansParameters.hpp" +#include "xmmKMeansResults.hpp" + +namespace xmm { +/** + @ingroup KMeans + @brief K-Means Clustering algorithm + */ +class KMeans : public Writable { + public: + static const unsigned int DEFAULT_MAX_ITERATIONS = 50; + static const float DEFAULT_RELATIVE_VARIATION_THRESHOLD() { return 1e-20; } + + /** + @brief Type of initizalization of the K-Means algorithm + */ + enum class InitializationMode { + /** + @brief random initialization (scaled using training set variance) + */ + Random, + + /** + @brief biased initialization: initialiazed with the first phrase + */ + Biased + }; + + /** + @brief Default Constructor + @param clusters number of clusters + */ + KMeans(unsigned int clusters = 1); + + /** + @brief Copy Constructor + @param src Source Model + */ + KMeans(KMeans const& src); + + /** + @brief Assignment + @param src Source Model + */ + KMeans& operator=(KMeans const& src); + + /** + @brief Train the K-Means clutering from the given training set + @param trainingSet Training Set + */ + void train(TrainingSet* trainingSet); + + /** + @brief Resets the fitering process (cluster association) + */ + void reset(); + + /** + @brief filters a incoming observation (performs cluster association) + @details the results of the inference process are stored in the results + attribute + @param observation observation vector + */ + void filter(std::vector<float> const& observation); + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + void fromJson(Json::Value const& root); + + ///@} + + /** + @brief Set of Parameters shared among classes + */ + std::shared_ptr<SharedParameters> shared_parameters; + + /** + @brief Configuration (default and class-specific parameters) + */ + Configuration<KMeans> configuration; + + /** + @brief Results of the cluster association after update with an observation + */ + Results<KMeans> results; + + /** + @brief Clusters centers + */ + std::vector<float> centers; + + /** + @brief Type of initialization for the K-Means Algorithm + */ + KMeans::InitializationMode initialization_mode; + + protected: + /** + @brief randomzie Cluster Centers (normalized width data variance) + of the first phrase of the training set + */ + void randomizeClusters(std::vector<float> const& trainingSetVariance); + + /** + @brief Initialize the clusters using a regular segmentation + of the first phrase of the training set + */ + void initClustersWithFirstPhrase(std::shared_ptr<Phrase> phrase); + + /** + @brief Update method for training + @details computes the cluster associated with each data points, and update + Cluster centers + */ + void updateCenters(std::vector<float>& previous_centers, + TrainingSet* trainingSet); +}; + +/** + @brief Simple Euclidian distance measure + @param vector1 first data point + @param vector2 first data point + @param dimension dimension of the data space + @return euclidian distance between the 2 points + */ +template <typename T> +T euclidean_distance(const T* vector1, const T* vector2, unsigned int dimension); +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansParameters.cpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansParameters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9620d0378dbc4a436b8d96c7993c1c29a8af8fd6 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansParameters.cpp @@ -0,0 +1,108 @@ +/* + * xmmKMeansParameters.hpp + * + * Parameters of the K-Means clustering Algorithm + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "xmmKMeansParameters.hpp" + +xmm::ClassParameters<xmm::KMeans>::ClassParameters() + : changed(true), + clusters(1, 1), + max_iterations(50, 1), + relative_distance_threshold(1e-20, 0) { + clusters.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + max_iterations.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + relative_distance_threshold.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); +} + +xmm::ClassParameters<xmm::KMeans>::ClassParameters( + ClassParameters<KMeans> const& src) + : changed(true), + clusters(src.clusters), + max_iterations(src.max_iterations), + relative_distance_threshold(src.relative_distance_threshold) { + clusters.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + max_iterations.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + relative_distance_threshold.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); +} + +xmm::ClassParameters<xmm::KMeans>::ClassParameters(Json::Value const& root) + : ClassParameters() { + clusters.set(root["clusters"].asInt()); + max_iterations.set(root["max_iterations"].asInt()); + relative_distance_threshold.set( + root["relative_distance_threshold"].asFloat()); +} + +xmm::ClassParameters<xmm::KMeans>& xmm::ClassParameters<xmm::KMeans>::operator=( + ClassParameters<KMeans> const& src) { + if (this != &src) { + changed = true; + clusters = src.clusters; + max_iterations = src.max_iterations; + relative_distance_threshold = src.relative_distance_threshold; + clusters.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + max_iterations.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + relative_distance_threshold.onAttributeChange( + this, &xmm::ClassParameters<xmm::KMeans>::onAttributeChange); + } + return *this; +} + +Json::Value xmm::ClassParameters<xmm::KMeans>::toJson() const { + Json::Value root; + root["clusters"] = static_cast<int>(clusters.get()); + root["max_iterations"] = static_cast<int>(max_iterations.get()); + root["relative_distance_threshold"] = relative_distance_threshold.get(); + return root; +} + +void xmm::ClassParameters<xmm::KMeans>::fromJson(Json::Value const& root) { + try { + ClassParameters<KMeans> tmp(root); + *this = tmp; + } catch (JsonException& e) { + throw e; + } +} + +void xmm::ClassParameters<xmm::KMeans>::onAttributeChange( + AttributeBase* attr_pointer) { + changed = true; + attr_pointer->changed = false; +} diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansParameters.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansParameters.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6f0e1d9f7fc15e22518ef8e3abfd94c2b242ee5 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansParameters.hpp @@ -0,0 +1,127 @@ +/* + * xmmKMeansParameters.hpp + * + * Parameters of the K-Means clustering Algorithm + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmKMeansParameters_hpp +#define xmmKMeansParameters_hpp + +#include "../../core/model/xmmModelParameters.hpp" + +namespace xmm { +/** + @defgroup KMeans [Models] K-Means Algorithm + */ + +/** + Dummy structure for template specialization + */ +class KMeans; + +/** + @ingroup KMeans + @brief Parameters specific to each class of a K-Means Algorithm + */ +template <> +class ClassParameters<KMeans> : public Writable { + public: + /** + @brief Default Constructor + */ + ClassParameters(); + + /** + @brief Copy Constructor + @param src Source Object + */ + ClassParameters(ClassParameters<KMeans> const& src); + + /** + @brief Constructor from Json Structure + @param root Json Value + */ + explicit ClassParameters(Json::Value const& root); + + /** + @brief Assignment + @param src Source Object + */ + ClassParameters& operator=(ClassParameters<KMeans> const& src); + + virtual ~ClassParameters() {} + + /** @name Json I/O */ + ///@{ + + /** + @brief Write the object to a JSON Structure + @return Json value containing the object's information + */ + Json::Value toJson() const; + + /** + @brief Read the object from a JSON Structure + @param root JSON value containing the object's information + @throws JsonException if the JSON value has a wrong format + */ + virtual void fromJson(Json::Value const& root); + + ///@} + + /** + @brief specifies if parameters have changed (model is invalid) + */ + bool changed = false; + + /** + @brief Number of Gaussian Mixture Components + */ + Attribute<unsigned int> clusters; + + /** + @brief Maximum number of iterations of the training update + */ + Attribute<unsigned int> max_iterations; + + /** + @brief threshold (as relative distance between cluster) required to define + convergence + */ + Attribute<float> relative_distance_threshold; + + protected: + /** + @brief notification function called when a member attribute is changed + */ + virtual void onAttributeChange(AttributeBase* attr_pointer); +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansResults.hpp b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansResults.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f327286fa6056abeff5b9470d1751ab1ef55bb89 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/models/kmeans/xmmKMeansResults.hpp @@ -0,0 +1,57 @@ +/* + * xmmKMeansResults.hpp + * + * Results of the K-Means clustering Algorithm + * + * Contact: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef xmmKMeansResults_h +#define xmmKMeansResults_h + +#include "../../core/model/xmmModelResults.hpp" + +namespace xmm { +/** + @ingroup KMeans + @brief Results of the clustering process + */ +template <> +struct Results<KMeans> { + /** + @brief Distance of the observation to each cluster + */ + std::vector<float> distances; + + /** + @brief Likeliest Cluster + */ + unsigned int likeliest; +}; +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/xmm.h b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/xmm.h new file mode 100644 index 0000000000000000000000000000000000000000..bb2112d01d7cf3fa2f0cfeaa88f1aa9e3c05cb2a --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/dependencies/xmm/src/xmm.h @@ -0,0 +1,450 @@ +/* + * xmm.h + * + * XMM - Probabilistic Models for Continuous Motion Recognition and Mapping + * ============================================================================ + * + * XMM is a portable, cross-platform C++ library that implements Gaussian + * Mixture Models and Hidden Markov Models for recognition and regression. + * The XMM library was developed for movement interaction in creative + * applications and implements an interactive machine learning workflow with + * fast training and continuous, real-time inference. + * + * Contact: + * - Jules Francoise: <jules.francoise@ircam.fr> + * + * + * Authors: + * - Jules Francoise <jules.francoise@ircam.fr> + * + * This code has been initially authored by Jules Francoise + * <http://julesfrancoise.com> during his PhD thesis, supervised by Frederic + * Bevilacqua <href="http://frederic-bevilacqua.net>, in the Sound Music + * Movement Interaction team <http://ismm.ircam.fr> of the + * STMS Lab - IRCAM, CNRS, UPMC (2011-2015). + * + * Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + * + * This project is released under the GPLv3 license. + * For commercial applications, a proprietary license is available upon + * request to Frederick Rousseau <frederick.rousseau@ircam.fr>. + * + * This File is part of XMM. + * + * XMM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * XMM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XMM. If not, see <http://www.gnu.org/licenses/>. + * + * Citing this work: + * If you use this code for research purposes, please cite one of the following + * publications: + * + * - J. Francoise, N. Schnell, R. Borghesi, and F. Bevilacqua, + * Probabilistic Models for Designing Motion and Sound Relationships. + * In Proceedings of the 2014 International Conference on New Interfaces + * for Musical Expression, NIME’14, London, UK, 2014. + * - J. Francoise, N. Schnell, and F. Bevilacqua, A Multimodal Probabilistic + * Model for Gesture-based Control of Sound Synthesis. In Proceedings of the + * 21st ACM international conference on Multimedia (MM’13), Barcelona, + * Spain, 2013. + */ + +#ifndef xmm_lib_xmm_h +#define xmm_lib_xmm_h + +#include "models/gmm/xmmGmm.hpp" +#include "models/hmm/xmmHierarchicalHmm.hpp" + +/** + @mainpage About + @anchor mainpage + @brief XMM is a portable, cross-platform C++ library that implements Gaussian + Mixture Models and Hidden Markov Models for + recognition and regression. The XMM library was developed for movement + interaction in creative applications and implements an + interactive machine learning workflow with fast training and continuous, + real-time inference. + + @par Contact + Jules Francoise: <jules.francoise@ircam.fr> + + @author + This code has been initially authored by <a + href="http://julesfrancoise.com">Jules Francoise</a> + during his PhD thesis, supervised by <a href="frederic-bevilacqua.net">Frederic + Bevilacqua</a>, in the + <a href="http://ismm.ircam.fr">Sound Music Movement Interaction</a> team of the + <a href="http://www.ircam.fr/stms.html?&L=1">STMS Lab</a> - IRCAM - CNRS - UPMC + (2011-2015). + + @copyright Copyright (C) 2015 UPMC, Ircam-Centre Pompidou. + + @par Licence + This project is released under the <a + href="http://www.gnu.org/licenses/gpl-3.0.en.html">GPLv3</a> license. + For commercial applications, a proprietary license is available upon request to + Frederick Rousseau <frederick.rousseau@ircam.fr>. @n@n + XMM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. @n@n + XMM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. @n@n + You should have received a copy of the GNU General Public License + along with XMM. If not, see <http://www.gnu.org/licenses/>. + + @par Citing this work + If you use this code for research purposes, please cite one of the following + publications: + - J. Francoise, N. Schnell, R. Borghesi, and F. Bevilacqua, Probabilistic + Models for Designing Motion and Sound Relationships. In Proceedings of the 2014 + International Conference on New Interfaces for Musical Expression, NIME’14, + London, UK, 2014. + - J. Francoise, N. Schnell, and F. Bevilacqua, A Multimodal Probabilistic Model + for Gesture-based Control of Sound Synthesis. In Proceedings of the 21st ACM + international conference on Multimedia (MM’13), Barcelona, Spain, 2013. + */ + +/** + @page GettingStarted Getting Started + + @section toc Table of Contents + + 1. @subpage Introduction @n + 2. @subpage Compilation @n + 3. @subpage examples_cpp @n + 4. @subpage examples_py @n +*/ + +#pragma mark - +#pragma mark Introduction + +/** + @page Introduction Introduction + @tableofcontents + + XMM is a portable, cross-platform C++ library that implements Gaussian Mixture + Models and Hidden Markov Models for + both recognition and regression. The XMM library was developed with interaction + as a central constraint and allows + for continuous, real-time use of the proposed methods. + @section why Why another HMM Library? + Several general machine learning toolkits have become popular over the years, + such as Weka in Java, Sckits-Learn in Python, + or more recently MLPack in C++. However, none of the above libraries were + adapted for the purpose of this thesis. As a matter + of fact, most HMM implementations are oriented towards classification and they + often only implement offline inference using + the Viterbi algorithm. + + In speech processing, the <a href="http://htk.eng.cam.ac.uk/">Hidden Markov + Model Toolkit (HTK)</a> has now become a standard + in Automatic Speech Recognition, and gave birth to a branch oriented towards + synthesis, called <a href="http://hts.sp.nitech.ac.jp/">HTS</a>. + Both libraries present many features specific to speech synthesis that do not + yet match our use-cases in movement and sound processing, + and have a really complex structure that does not facilitate embedding. + + Above all, we did not find any library explicitly implementing the Hierarchical + HMM, nor the regression methods based on + GMMs and HMMs. For these reasons, we decided to start of novel implementation + of these methods with the following + constraints: + - __Real-Time:__ Inference must be performed in continuously, meaning that the + models must update their internal state and prediction + at each new observation to allow continuous recognition and generation. + + - __Interactive:__ The library must be compatible with an interactive learning + workflow, that allows users to easily define and edit + training sets, train models, and evaluate the results through direct + interaction. + All models must be able to learn from few examples (possibly a single + demonstration). + + - __Portable:__ In order to be integrated within various software, platforms, + the library must be portable, cross-platform, and lightweight. + + We chose C++ that is both efficient and easy to integrate within other software + and languages such as Max and Python. + We now detail the four models that are implemented to date, the architecture of + the library as well as the proposed + Max/MuBu implementation with several examples. + @section fourmodels Four Models + The implemented models are summarized in Table the following table. + Each of the four model addresses a different combination of the multimodal and + temporal aspects. + We implemented two instantaneous models based on Gaussian Mixture Models and + two temporal models with a hierarchical + structure, based on an extension of the basic Hidden Markov Model (HMM) + formalism. + \ | Movement | Multimodal + ------------- | ------------- | ------------- + Instantaneous | Gaussian Mixture Model (GMM) | Gaussian Mixture Regression + (GMR) + Temporal | Hierarchical Hidden Markov Model(HHMM) | Multimodal Hierarchical + Hidden Markov Model(MHMM) + + - __Gaussian Mixture Models (GMMs)__ are instantaneous movement models. + The input data associated to a class defined by the training sets is abstracted + by a mixture (i.e.\ a weighted sum) of Gaussian distributions. + This representation allows recognition in the _performance_ phase: for each + input frame the model calculates the likelihood of each + class (Figure 1 (__a__)). + + - __Gaussian Mixture Regression (GMR)__ are a straightforward extension of + Gaussian Mixture Models used for regression. + Trained with multimodal data, GMR allows for predicting the features of one + modality (e.g. sound) from the features + of another (e.g. movement) through non-linear regression between both feature + sets (Figure 1 (__b__)). + + - __Hierarchical HMM (HHMM)__ integrates a high-level structure that governs + the transitions between classical HMM structures representing the + temporal evolution of --- low-level --- movement segments. In the _performance_ + phase of the system, the hierarchical model estimates the likeliest + gesture according to the transitions defined by the user. The system + continuously estimates the likelihood for each model, as well as the time + progression within the original training phrases (Figure 1 (__c__)). + + - __Multimodal Hierarchical HMM (MHMM)__ allows for predicting a stream of + sound parameters from a stream of movement features. + It simultaneously takes into account the temporal evolution of movement and + sound as well as their dynamic relationship according + to the given example phrases. In this way, it guarantees the temporal + consistency of the generated sound, while realizing the trained + temporal movement-sound mappings (Figure 1 (__d__)). + + @image html xmm_models.jpg "Figure 1: Schematic Representation of the 4 + implemented models" + + @section architecture Architecture + Our implementation has a particular attention to the interactive training + procedure, and to the respect of the + real-time constraints of the _performance_ mode. + The library is built upon four components representing phrases, training sets, + models and model groups, as represented + on Figure 2. + A phrase is a multimodal data container used to store training examples. + A training set is used to aggregate phrases associated with labels. It provides + a set of function for interactive + recording, editing and annotation of the phrases. + Each instance of a model is connected to a training set that provides access to + the training phrases. + Performance functions are designed for real-time usage, updating the internal + state of the model and the results for + each new observation of a new movement. + The library is portable and cross-platform. It defines a specific format for + exchanging trained models, and provides + Python bindings for scripting purpose or offline processing. + @image html xmm_architecture.jpg "Figure 2: Architecture of the XMM library" + + @section relatedpubs Related Publications + * J. Francoise, N. Schnell, R. Borghesi, and F. Bevilacqua, Probabilistic + Models for Designing Motion and Sound Relationships. In Proceedings of the 2014 + International Conference on New Interfaces for Musical Expression, NIME’14, + London, UK, 2014. <a + href="http://julesfrancoise.com/blog/wp-content/uploads/2014/06/Fran%C3%A7oise-et-al.-2014-Probabilistic-Models-for-Designing-Motion-and-Sound-Relationships.pdf?1ce945">Download</a> + + * J. Francoise, N. Schnell, and F. Bevilacqua, A Multimodal Probabilistic Model + for Gesture-based Control of Sound Synthesis. In Proceedings of the 21st ACM + international conference on Multimedia (MM’13), Barcelona, Spain, 2013. <a + href="http://architexte.ircam.fr/textes/Francoise13b/index.pdf">Download</a> + + <center>Prev: \ref mainpage "Home" | Next: \ref Compilation.</center> + */ + +#pragma mark - +#pragma mark Compilation and Usage + +/** + @page Compilation Compilation and Usage + @tableofcontents + + @section Dependencies + The library depends on <a + href="https://github.com/open-source-parsers/jsoncpp">jsoncpp</a> for JSON file + I/O. The library is distributed with this softare. The units tests rely on the + <a href="https://github.com/philsquared/Catch">Catch</a> testing framework@n + + @section lib Compiling as a static/dynamic library + @subsection xcodelib XCode + See the xcode project in "ide/xcode/" + + @subsection cmakelib CMake + The library can be built using <a href="http://www.cmake.org/">CMake</a>.@n + In the root directory, type the following command to generate the Makefiles: + @code + cmake . -G"Unix Makefiles" + @endcode + The following commands can be used to build the static library, run the unit + tests, and generate the documentation: + @code + make + make test + make doc + @endcode + + @subsection cppusage Usage + + The header file "xmm.h" includes all useful headers of the library. + + @section python Building the Python Library + @subsection dependencies Dependencies + - <a href="http://www.doxygen.org/">doxygen</a> + - <a href="http://www.swig.org/">swig</a> + - <a href="http://www.numpy.org/">Numpy</a> + - <a href="http://matplotlib.org/">Matplotlib</a> (for plotting utilities) + + @subsection pythonbuild Building + The python module can be built using <a + href="http://www.cmake.org/">CMake</a>.@n + In the python directory, type the following command to generate the Makefiles + and build the python module: + @code + cmake . -G"Unix Makefiles" + make + @endcode + The module should be installed in "${xmm_root}/python/bin/" + + @subsection usage Usage + Place the built python library somewhere in your python path. To add personal + libraries located in '/Path/To/Libs' to the python path, add the following + lines to your ".bash_profile": + + @code + PYTHONPATH=$PYTHONPATH:/Path/To/Libs + export PYTHONPATH + @endcode + + To import the library in python: + @code + >>> import xmm + @endcode + + Additional utilities can be found in `xmm.util`. + <center>Prev: \ref Introduction | Next: \ref examples_cpp.</center> + */ + +#pragma mark - +#pragma mark Getting Started in C++ + +/** + @page examples_cpp Getting Started in C++ + @tableofcontents + + TODO. + + <center>Prev: \ref Compilation | Next: \ref examples_py.</center> + + */ + +#pragma mark - +#pragma mark Getting Started in Python + +/** + @page examples_py Getting Started in Python + @tableofcontents + + TODO. + + @section pyexamples Python Examples + + Several examples are included in the ipython notebook IPython Notebook: + `python/examples/QuickStart_Python.ipynb` @n + We report here the static html version of the notebook: + + @htmlinclude QuickStart_Python.html + */ + +#pragma mark - +#pragma mark Documentation + +/** + @page Documentation Documentation + + This page contains the detailed documentation of the library (generated by + Doxygen). + + <ul> + <li><a href="modules.html">Modules</a></li> + <li><a href="annotated.html">Class List</a></li> + <li><a href="inherits.html">Class Hierarchy</a></li> + </ul> + + */ + +#pragma mark - +#pragma mark Download + +/** + @page Download Download + @tableofcontents + + @section cpplib C++ Library + + The source code is available on __Github__: https://github.com/Ircam-RnD/xmm + + @section maxmubu Max/MuBu Implementation + The models are integrated with the <a + href="http://ismm.ircam.fr/mubu/">MuBu</A> environment within + <a href="http://cycling74.com/">Cycling 74 Max</a> that provides a consistent + framework for motion/sound feature extraction + and pre-processing; interactive recording, editing, and annotation of the + training sets; and interactive sound synthesis. + MuBu is freely available on <a + href="http://forumnet.ircam.fr/product/mubu/">Ircam's Forumnet</a>. + + Max is a visual programming environment dedicated to music and interactive + media. + We provide an implementation of our library as a set of Max externals and + abstractions articulated around the _MuBu_ collection of objects developed at + Ircam. + Training sets are built using _MuBu_, a generic container designed to store and + process multimodal data such as audio, motion tracking data, sound descriptors, + markers, etc. + Each training phrase is stored in a buffer of the container, and movement and + sound parameters are recorded into separate tracks of each buffer. + Markers can be used to specify regions of interest within the recorded + examples. + Phrases are labeled using the markers or as an attribute of the buffer. + This structure allows users to quickly record, modify, and annotate the + training examples. + Training sets are thus autonomous and can be used to train several models. + + Each model can be instantiated as a max object referring to a MuBu container + that defines its training set. + For training, the model connects to the container and transfers the training + examples to its internal representation of phrases. + The parameters of the model can be set manually as attributes of the object, + such as the number of Gaussian components in the case of a GMM, or the number + of states in the case of a HMM. + The training is performed in background. + + For performance, each object processes an input stream of movement features and + updates the results with the same rate. + For movement models, the object output the list of likelihoods, complemented + with the parameters estimated for each class, such as the time progression in + the case of a temporal model, or the weight of each Gaussian component in the + case of a GMM. + For multimodal models, the object also outputs the most probable sound + parameters estimated by the model, that can be directly used to drive the sound + synthesis. + + @section ofx_addon OpenFrameworks Addon + + Coming Soon... + + */ + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/libRAPID-MIX_API.a b/examples/ofx/Bitalino_rapidmix/libRAPID-MIX_API.a new file mode 100644 index 0000000000000000000000000000000000000000..a2313c41e6ce03bf4053303a8516fcbcc0580e62 Binary files /dev/null and b/examples/ofx/Bitalino_rapidmix/libRAPID-MIX_API.a differ diff --git a/examples/ofx/Bitalino_rapidmix/openFrameworks-Info.plist b/examples/ofx/Bitalino_rapidmix/openFrameworks-Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..8d64d2b38e591af1246f436ea77860cbb7089f66 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/openFrameworks-Info.plist @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIdentifier</key> + <string>cc.openFrameworks.ofapp</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>CFBundleIconFile</key> + <string>${ICON}</string> +</dict> +</plist> diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/LICENSE b/examples/ofx/Bitalino_rapidmix/rapid-mix/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..b9a6377cec4eaff81619682d672af953257ec9bd --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2017 Goldsmiths College University of London +Copyright (c) 2017 by IRCAM – Centre Pompidou, Paris, France +All rights reserved. + +The RAPID-MIX API wrapper, in the /src directory, is licenced by the BSD license below. Submodules in the /dependances +folder have their own copyrights and licenses, including MIT, BSD, and GPLv3 licenses. Users are requested to check +individual folders for license details, or to contact RAPID-MIX developers. + +BSD 3-clause + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. + +- Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/machineLearning.cpp b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/machineLearning.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11d7153d301cf2023304cc56eabb15628328d48e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/machineLearning.cpp @@ -0,0 +1,91 @@ +/** + * @file machineLearning.cpp + * @author Michael Zbyszynski + * @date 10 Jan 2016 + * @copyright + * Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include "machineLearning.h" + +namespace rapidmix { + + //////////////////////////////////////////////////////////////////////// Generic train + template <class MachineLearningModule> + bool machineLearning<MachineLearningModule>::train(const trainingData &newTrainingData) { + return MachineLearningModule::train(newTrainingData); + } + + + /////////////////////////////////////////////////////////////////////// RapidLib specializations + + void trainingData2rapidLib (const trainingData &newTrainingData, std::vector<trainingExample> &trainingSet) { + for (int h = 0; h < newTrainingData.trainingSet.size(); ++h) { //Go through every phrase + + for (int i = 0; i < newTrainingData.trainingSet[h].elements.size(); ++i) { //...and every element + trainingExample tempExample; + tempExample.input = newTrainingData.trainingSet[h].elements[i].input; + if (newTrainingData.trainingSet[h].elements[i].output.size() > 0) { + tempExample.output = newTrainingData.trainingSet[h].elements[i].output; + } else { + tempExample.output.push_back(double(h)); + } + trainingSet.push_back(tempExample); + } + } + }; + + /////////////////////////////////////////////////////////////////////// RapidLib classification + template<> + bool machineLearning<classification>::train(const trainingData &newTrainingData) { + std::vector<trainingExample> trainingSet; + labels.clear(); + for (int i = 0; i < newTrainingData.trainingSet.size(); ++i) { + labels.push_back(newTrainingData.trainingSet[i].label); + } + trainingData2rapidLib(newTrainingData, trainingSet); + return classification::train(trainingSet); + } + + /////////////////////////////////////////////////////////////////////// RapidLib regression + template<> + bool machineLearning<regression>::train(const trainingData &newTrainingData) { + std::vector<trainingExample> trainingSet; + trainingData2rapidLib(newTrainingData, trainingSet); + return regression::train(trainingSet); + } + + /////////////////////////////////////////////////////////////////////// RapidLib seriesClassification + template<> + bool machineLearning<seriesClassification>::train(const trainingData &newTrainingData) { + std::vector<trainingSeries> seriesSet; + for (int i = 0; i < newTrainingData.trainingSet.size(); ++i) { //each phrase + trainingSeries tempSeries; + tempSeries.label = newTrainingData.trainingSet[i].label; + for (int j = 0; j < newTrainingData.trainingSet[i].elements.size(); ++j) { //each element + tempSeries.input.push_back(newTrainingData.trainingSet[i].elements[j].input); + } + seriesSet.push_back(tempSeries); + } + return seriesClassification::train(seriesSet); + } + + template<> + std::string machineLearning<classification>::run(const std::vector<double> &inputVector, const std::string &label) { + int classIndex = classification::run(inputVector)[0]; + return labels[classIndex]; + }; + + template<> + std::string machineLearning<seriesClassification>::run(const std::vector<std::vector<double> > &inputSeries) { + return seriesClassification::run(inputSeries); + } + + + /////////////////////////////////////////////////////////////////////// GVF + template<> + bool machineLearning<rapidGVF>::train(const trainingData &newTrainingData) { + return rapidGVF::train(newTrainingData); + } + +} diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/machineLearning.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/machineLearning.h new file mode 100644 index 0000000000000000000000000000000000000000..80c101d81ad093eff06fa1b78852ad5915916837 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/machineLearning.h @@ -0,0 +1,113 @@ +/** + * @file machineLearning.h + * @author Michael Zbyszynski on 10 Jan 2016 + * @copyright + * Copyright © 2017 Goldsmiths. All rights reserved. + * + * @ingroup machinelearning + */ + +#ifndef machineLearning_h +#define machineLearning_h + +#include "rapidmix.h"///////// Include all of the machine learning algorithms here +#include "classification.h" +#include "regression.h" +#include "seriesClassification.h" +#include "rapidXMM.h" +#include "rapidGVF.h" + +namespace rapidmix { + + // forward declaration + class trainingData; + + /** @brief A generic ouptut struct to fit all kinds of models */ + typedef struct runResults_t { + std::vector<double> likelihoods; + std::vector<double> regression; + std::vector<double> progressions; + std::string likeliest; + } runResults; + + /** + * @brief Host class for machine learning algorithms + */ + template <typename MachineLearningModule> + class machineLearning : public MachineLearningModule { + public: + + //* Constructors */ + machineLearning() : MachineLearningModule() {}; + + template<class T> + machineLearning(T type) : MachineLearningModule(type) {}; + + /** + * @brief This function becomes specialized in the implementation + */ + bool train(const trainingData &newTrainingData); + + // This is a hack while I think about how to do this. -MZ // + std::string run(const std::vector<double> &inputVector, const std::string &label); + + //* This is the one I'm using for DTW */ + std::string run(const std::vector<std::vector<double> > &inputSeries); + + //* this function is not being specialized + std::vector<double> run(const std::vector<double> &inputVector) { + return MachineLearningModule::run(inputVector); + } + + bool reset() { + return MachineLearningModule::reset(); + } + + private: + MachineLearningModule module; + + //this holds string labels + std::vector<std::string> labels; //FIXME: This probably should be pushed down into rapidLib? + std::string getLabel(int value); + + }; + + ////////// typedefs for calling different algorithms + + ///// RapidLib + + /** @brief static classification using KNN from RapidLib */ + typedef machineLearning<classification> staticClassification; + + /** @brief static regression using Neural Networks from RapidLib */ + typedef machineLearning<regression> staticRegression; + + /** @brief temporal classification using Dynamic Time Warping from RapidLib */ + typedef machineLearning<seriesClassification> dtwTemporalClassification; + + ///// XMM + + /** @brief configuration for XMM based algorithms */ + typedef xmmToolConfig xmmConfig; + + /** @brief static classification using Gaussian Mixture Models from XMM */ + typedef machineLearning<rapidXmmGmm> xmmStaticClassification; + + /** @brief static regression using Gaussian Mixture Models from XMM */ + typedef machineLearning<rapidXmmGmr> xmmStaticRegression; + + /** @brief temporal classification using Hierarchical Hidden Markov Models from XMM */ + typedef machineLearning<rapidXmmHmm> xmmTemporalClassification; + + /** @brief temporal regression using Hierarchical Hidden Markov Models from XMM */ + typedef machineLearning<rapidXmmHmr> xmmTemporalRegression; + + ///// GVF + + /** @brief temporal variation estimation using GVF library */ + typedef machineLearning<rapidGVF> gvfTemporalVariation; + + +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidGVF/rapidGVF.cpp b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidGVF/rapidGVF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f051fddd888e858d51b6a47f6817a23b7b4e8fb --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidGVF/rapidGVF.cpp @@ -0,0 +1,86 @@ +// +// rapidGVF.cpp +// +// Created by Francisco on 04/05/2017. +// Copyright © 2017 Goldsmiths. All rights reserved. +// + +#include "rapidGVF.h" +#include "trainingData.h" + +rapidGVF::rapidGVF() +{ + // Initialised with default configuration + this->gvf = new GVF(); + this->currentGesture = GVFGesture(); +} + +rapidGVF::~rapidGVF() +{ + delete this->gvf; + this->currentGesture = NULL; +} + +bool rapidGVF::train(const rapidmix::trainingData &newTrainingData) { + + if (newTrainingData.trainingSet.size() < 1) { + // no recorded phrase + return false; + } + + if (newTrainingData.trainingSet.size() == 1 && newTrainingData.trainingSet[0].elements.size() == 0) { + // empty recorded phrase + return false; + } + + if(gvf->getState() != GVF::STATE_LEARNING) + { + gvf->setState(GVF::STATE_LEARNING); + } + + //Go through every phrase + + for (int h = 0; h < newTrainingData.trainingSet.size(); ++h) { //I changed this because the default set is gone. -MZ + this->gvf->startGesture(); + for (int i = 0; i < newTrainingData.trainingSet[h].elements.size(); ++i) { + + std::vector<double> vd = newTrainingData.trainingSet[h].elements[i].input; + + // Using template <class InputIterator> vector to change for vec<double> to vec<float> + std::vector<float> vf(vd.begin(), vd.end()); + this->currentGesture.addObservation(vf); + } + this->gvf->addGestureTemplate(this->currentGesture); + } + return true; +} + +std::vector<double> rapidGVF::run(const std::vector<double> &inputVector){ + + if (inputVector.size() == 0) { + return std::vector<double>(); + } + + gvf->restart(); + + if(gvf->getState() != GVF::STATE_FOLLOWING) + { + gvf->setState(GVF::STATE_FOLLOWING); + } + + // Using template <class InputIterator> vector to change for vec<double> to vec<float> + std::vector<float> vf(inputVector.begin(),inputVector.end()); + + this->currentGesture.addObservation(vf); + this->outcomes = this->gvf->update(this->currentGesture.getLastObservation()); + + std::vector<double> output; + output.push_back(this->outcomes.likeliestGesture); + output.insert(output.end(), this->outcomes.likelihoods.begin(), this->outcomes.likelihoods.end()); + output.insert(output.end(), this->outcomes.alignments.begin(), this->outcomes.alignments.end()); +// output.insert(output.end(), this->outcomes.dynamics.begin(), this->outcomes.dynamics.end()); +// output.insert(output.end(), this->outcomes.scalings.begin(), this->outcomes.scalings.end()); +// output.insert(output.end(), this->outcomes.rotations.begin(), this->outcomes.rotations.end()); +// + return output; +} diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidGVF/rapidGVF.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidGVF/rapidGVF.h new file mode 100644 index 0000000000000000000000000000000000000000..88e667a69cc9c5425618206a38c14baa7e68bfb9 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidGVF/rapidGVF.h @@ -0,0 +1,37 @@ +/** + * @file rapidGVF.h + * Created by Francisco on 04/05/2017. + * Copyright © 2017 Goldsmiths. All rights reserved. + * + * @ingroup machinelearning + */ + +#ifndef rapidGVF_h +#define rapidGVF_h + +#include <vector> +#include <string> +#include "GVF.h" + +namespace rapidmix { class trainingData; } + +/** + * @brief This class is an adapter for the GVF library from Baptiste Caramiaux + */ +class rapidGVF { + +public: + rapidGVF(); + ~rapidGVF(); + + bool train(const rapidmix::trainingData &newTrainingData); + std::vector<double> run(const std::vector<double> &inputVector); + //TODO: needs a "reset" message + +protected: + GVF * gvf; + GVFGesture currentGesture; + GVFOutcomes outcomes; +}; + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidXMM/rapidXMM.cpp b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidXMM/rapidXMM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..799a429bf6b0673dcd8680992cd01c46bdf47d43 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidXMM/rapidXMM.cpp @@ -0,0 +1,208 @@ +#include "rapidXMM.h" +#include "trainingData.h" +#include "machineLearning.h" + +static bool trainingData2xmmTrainingSet(const rapidmix::trainingData& data, xmm::TrainingSet& set) { + if (data.trainingSet.size() < 1) { + return false; + } + + if (data.trainingSet.size() > 0 && data.trainingSet[0].elements.size() == 0) { + // empty recorded phrase + return false; + } + + rapidmix::trainingData::element el = data.trainingSet[0].elements[0]; + int dimIn = static_cast<int>(el.input.size()); + int dimOut = static_cast<int>(el.output.size()); + + // translate and return true if data and set are compatible + // don't translate and return false otherwise + + if (dimOut > 0 != set.bimodal()) { + return false; + } + + xmm::Phrase xp; + + if (set.bimodal()) { + set.dimension.set(dimIn + dimOut); + set.dimension_input.set(dimIn); + xp = xmm::Phrase(xmm::MemoryMode::OwnMemory, xmm::Multimodality::Bimodal); + xp.dimension.set(dimIn + dimOut); + xp.dimension_input.set(dimIn); + } else { + set.dimension.set(dimIn); + set.dimension_input.set(0); + xp = xmm::Phrase(xmm::MemoryMode::OwnMemory, xmm::Multimodality::Unimodal); + xp.dimension.set(dimIn); + xp.dimension_input.set(0); + } + + set.clear(); + + //for (auto &phrase : data.trainingSet) { + for (int i = 0; i < data.trainingSet.size(); ++i) { + const rapidmix::trainingData::phrase &phrase = data.trainingSet[i]; + xp.clear(); + xp.label.set(phrase.label); + + for (auto &element : phrase.elements) { + std::vector<float> obsIn(element.input.begin(), element.input.end()); + std::vector<float> obsOut(element.output.begin(), element.output.end()); + std::vector<float> obs; + obs.insert(obs.end(), obsIn.begin(), obsIn.end()); + obs.insert(obs.end(), obsOut.begin(), obsOut.end()); + xp.record(obs); + } + + set.addPhrase(static_cast<int>(set.size()), xp); + } + + return true; +} + +//=============================== xmmTool ====================================// + +template <class SingleClassModel, class Model> +bool xmmTool<SingleClassModel, Model>::train(const rapidmix::trainingData& newTrainingData) { + if (trainingData2xmmTrainingSet(newTrainingData, set)) { + model.train(&set); + model.reset(); + return true; + } + + return false; +} + +////////// private JSON data manipulation methods : + +//TODO: add a type field (gmm/gmr/hmm/hmr) in metadata when family is xmm +template <class SingleClassModel, class Model> +Json::Value xmmTool<SingleClassModel, Model>::toJSON(/*std::string modelType*/) { + Json::Value root; + Json::Value metadata; + Json::Value modelSet; + + metadata["creator"] = "Rapid API C++"; + metadata["version"] = "v0.1.1"; //TODO: This should be a macro someplace + metadata["family"] = "xmm"; + root["metadata"] = metadata; + + modelSet.append(model.toJson()); + root["modelSet"] = modelSet; + + return root; +} + +template <class SingleClassModel, class Model> +bool xmmTool<SingleClassModel, Model>::fromJSON(Json::Value &jm) { + if (jm["metadata"]["family"].asString().compare("xmm") == 0 && + jm["modelSet"].size() > 0) { + model.fromJson(jm["modelSet"][0]); + model.reset(); + return true; + } + + return false; +} + +////////// public JSON file manipulation interface : + +template <class SingleClassModel, class Model> +std::string xmmTool<SingleClassModel, Model>::getJSON() { + Json::Value result = toJSON(); + return result.toStyledString(); +} + +template <class SingleClassModel, class Model> +void xmmTool<SingleClassModel, Model>::writeJSON(const std::string &filepath) { + Json::Value root = toJSON(); + std::ofstream jsonOut; + jsonOut.open (filepath); + Json::StyledStreamWriter writer; + writer.write(jsonOut, root); + jsonOut.close(); +} + +template <class SingleClassModel, class Model> +bool xmmTool<SingleClassModel, Model>::putJSON(const std::string &jsonMessage) { + Json::Value parsedFromString; + Json::Reader reader; + bool parsingSuccessful = reader.parse(jsonMessage, parsedFromString); + return (parsingSuccessful && fromJSON(parsedFromString)); +} + +template <class SingleClassModel, class Model> +bool xmmTool<SingleClassModel, Model>::readJSON(const std::string &filepath) { + Json::Value root; + std::ifstream file(filepath); + file >> root; + return fromJSON(root); +} + +//============================== xmmGmmTool ==================================// + +// std::vector<double> xmmGmmTool::run(const std::vector<double>& inputVector) { +std::vector<double> rapidXmmGmm::run(const std::vector<double>& inputVector) { + xmmTool::preProcess(inputVector); + return model.results.smoothed_normalized_likelihoods; +} + +//============================== xmmGmrTool ==================================// + +// std::vector<double> xmmGmrTool::run(const std::vector<double>& inputVector) { +std::vector<double> rapidXmmGmr::run(const std::vector<double>& inputVector) { + xmmTool::preProcess(inputVector); + std::vector<float> *res = &model.results.output_values; + std::vector<double> dRes(res->begin(), res->end()); + return dRes; +} + +//============================== xmmHmmTool ==================================// + +// std::vector<double> xmmHmmTool::run(const std::vector<double>& inputVector) { +std::vector<double> rapidXmmHmm::run(const std::vector<double>& inputVector) { + xmmTool::preProcess(inputVector); + std::vector<double> res; + + int i(0); + for (auto &m : model.models) { + res.push_back(model.results.smoothed_normalized_likelihoods[i]); + res.push_back(m.second.results.progress); + i++; + } + + return res; +} + +//============================== xmmHmrTool ==================================// + +// std::vector<double> xmmHmrTool::run(const std::vector<double>& inputVector) { +std::vector<double> rapidXmmHmr::run(const std::vector<double>& inputVector) { + xmmTool::preProcess(inputVector); + std::vector<float> *res = &model.results.output_values; + std::vector<double> dRes(res->begin(), res->end()); + return dRes; +} + +/////////////////////////////////////////////////////////////////////////// +///// generic train method and forward declaration of specialized templates +/////////////////////////////////////////////////////////////////////////// + +//I wonder why this can't be defined in machineLearning.cpp? -MZ + +template <class MachineLearningModule> +bool rapidmix::machineLearning<MachineLearningModule>::train(const trainingData &newTrainingData) { + return MachineLearningModule::train(newTrainingData); +} + +// template class rapidmix::machineLearning<xmmGmmTool>; +// template class rapidmix::machineLearning<xmmGmrTool>; +// template class rapidmix::machineLearning<xmmHmmTool>; +// template class rapidmix::machineLearning<xmmHmrTool>; +template class rapidmix::machineLearning<rapidXmmGmm>; +template class rapidmix::machineLearning<rapidXmmGmr>; +template class rapidmix::machineLearning<rapidXmmHmm>; +template class rapidmix::machineLearning<rapidXmmHmr>; + diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidXMM/rapidXMM.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidXMM/rapidXMM.h new file mode 100644 index 0000000000000000000000000000000000000000..e87f992dfe79fd285d2ed621108b90fdd8304064 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/rapidXMM/rapidXMM.h @@ -0,0 +1,296 @@ +/** + * @file rapidXMM.h + * @author joseph larralde + * + * @copyright + * Copyright (C) 2016 - 2017 by IRCAM - Centre Pompidou, Paris, France. + * All rights reserved. + * + * @ingroup machinelearning + */ + +#ifndef _RAPID_XMM_TOOLS_H_ +#define _RAPID_XMM_TOOLS_H_ + +// this works ! +#ifndef EXTERNAL_JSONCPP_PATH +// #define EXTERNAL_JSONCPP_PATH "../../../../json/json.h" // relative to xmmJson.h +#define EXTERNAL_JSONCPP_PATH "json.h" +#endif /* EXTERNAL_JSONCPP_PATH */ + +#include "xmm.h" + +// forward declaration +namespace rapidmix { class trainingData; } + +// original defined in xmmModelConfiguration.hpp +enum xmmRegressionEstimator { + xmmLikeliestRegression, + xmmMixtureRegression +}; + +// original defined in xmmGaussianDistribution.hpp +enum xmmCovarianceMode { + xmmFullCovariance, + xmmDiagonalCovariance +}; + +// original defined in xmmHmmParameters.hpp +enum xmmHmmTransitionMode { + xmmHmmLeftRightTransition, + xmmHmmErgodicTransition +}; + +// original defined in xmmHmmParameters.hpp +enum xmmHmmRegressionEstimator { + xmmHmmFullRegression, + xmmHmmWindowedRegression, + xmmHmmLikeliestRegression +}; + +// this is the optional argument of machineLearning<xmmWhateverTool>'s constructors +struct xmmToolConfig { + xmmToolConfig() : + gaussians(1), + relativeRegularization(0.01), + absoluteRegularization(0.01), + regressionEstimator(xmmMixtureRegression), + covarianceMode(xmmFullCovariance), + states(5), + hierarchical(true), + hmmTransitionMode(xmmHmmErgodicTransition), + hmmRegressionEstimator(xmmHmmFullRegression), + likelihoodWindow(5) {} + + // general parameters : + uint32_t gaussians; + float relativeRegularization; + float absoluteRegularization; + xmmRegressionEstimator regressionEstimator; + xmmCovarianceMode covarianceMode; + + // hmm specific : + uint32_t states; + bool hierarchical; + xmmHmmTransitionMode hmmTransitionMode; + xmmHmmRegressionEstimator hmmRegressionEstimator; + + // run-time parameter : + uint32_t likelihoodWindow; +}; + +//========================== template base class =============================// + +template <class SingleClassModel, class Model> +class xmmTool { +protected: + xmmTool(bool bimodal) { + model = Model(bimodal); + model.configuration.multithreading = xmm::MultithreadingMode::Sequential; + model.configuration.changed = true; + + set = xmm::TrainingSet(xmm::MemoryMode::OwnMemory, + bimodal + ? xmm::Multimodality::Bimodal + : xmm::Multimodality::Unimodal + ); + } + + virtual void preProcess(const std::vector<double> &inputVector) { + std::vector<float> fv(inputVector.begin(), inputVector.end()); + model.filter(fv); + } + +public: + virtual ~xmmTool() {} + + virtual bool train(const rapidmix::trainingData &newTrainingData); + + virtual bool reset() { + model.reset(); + return true; + } + + /** Get a JSON representation of the model in the form of a styled string */ + virtual std::string getJSON(); + /** Write a JSON model description to specified file path */ + virtual void writeJSON(const std::string &filepath); + /** configure empty model with string. See getJSON() */ + virtual bool putJSON(const std::string &jsonMessage); + /** read a JSON file at file path and build a modelSet from it */ + virtual bool readJSON(const std::string &filepath); + +protected: + Model model; + xmm::TrainingSet set; + + Json::Value toJSON(); + bool fromJSON(Json::Value &jm); +}; + +//======================= base class for GMM models ==========================// + +template <class SingleClassModel, class Model> +class xmmStaticTool : public xmmTool<SingleClassModel, Model> { +protected: + xmmStaticTool(xmmToolConfig cfg, bool bimodal) : + xmmTool<SingleClassModel, Model>(bimodal) { + xmm::Configuration<SingleClassModel>& mCfg = this->model.configuration; + + mCfg.gaussians.set(cfg.gaussians); + mCfg.relative_regularization.set(cfg.relativeRegularization); + mCfg.absolute_regularization.set(cfg.absoluteRegularization); + + xmm::MultiClassRegressionEstimator mcre; + switch (cfg.regressionEstimator) { + case xmmLikeliestRegression: + mcre = xmm::MultiClassRegressionEstimator::Likeliest; + case xmmMixtureRegression: + default: + mcre = xmm::MultiClassRegressionEstimator::Mixture; + break; + } + mCfg.multiClass_regression_estimator = mcre; + + xmm::GaussianDistribution::CovarianceMode gdcm; + switch (cfg.covarianceMode) { + case xmmFullCovariance: + gdcm = xmm::GaussianDistribution::CovarianceMode::Full; + break; + case xmmDiagonalCovariance: + default: + gdcm = xmm::GaussianDistribution::CovarianceMode::Diagonal; + break; + } + mCfg.covariance_mode.set(gdcm); + + mCfg.changed = true; + + this->model.shared_parameters->likelihood_window.set(cfg.likelihoodWindow); + } + +public: + virtual ~xmmStaticTool() {} +}; + +//======================= base class for HMM models ==========================// + +template <class SingleClassModel, class Model> +class xmmTemporalTool : public xmmStaticTool<SingleClassModel, Model> { +protected: + xmmTemporalTool(xmmToolConfig cfg, bool bimodal) : + xmmStaticTool<SingleClassModel, Model>(cfg, bimodal) { + xmm::Configuration<SingleClassModel>& mCfg = this->model.configuration; + + mCfg.states.set(cfg.states); + mCfg.hierarchical.set(cfg.hierarchical); + + xmm::HMM::TransitionMode htm; + switch (cfg.hmmTransitionMode) { + case xmmHmmLeftRightTransition: + htm = xmm::HMM::TransitionMode::LeftRight; + break; + case xmmHmmErgodicTransition: + default: + htm = xmm::HMM::TransitionMode::Ergodic; + break; + } + mCfg.transition_mode.set(htm); + + xmm::HMM::RegressionEstimator hre; + switch (cfg.hmmRegressionEstimator) { + case xmmHmmFullRegression: + hre = xmm::HMM::RegressionEstimator::Full; + break; + case xmmHmmWindowedRegression: + hre = xmm::HMM::RegressionEstimator::Windowed; + break; + case xmmHmmLikeliestRegression: + default: + hre = xmm::HMM::RegressionEstimator::Likeliest; + break; + } + mCfg.regression_estimator.set(hre); + + mCfg.changed = true; + } + +public: + virtual ~xmmTemporalTool() {} +}; + +//================== actual classes used in machineLearning.h ================// + +/** + * @brief Static classification using Gaussian Mixture Models + */ +// class xmmGmmTool : public xmmStaticTool<xmm::GMM, xmm::GMM> { +// class GMM : public xmmStaticTool<xmm::GMM, xmm::GMM> { +class rapidXmmGmm : public xmmStaticTool<xmm::GMM, xmm::GMM> { +public: + // xmmGmmTool(xmmToolConfig cfg = xmmToolConfig()) : + // GMM(xmmToolConfig cfg = xmmToolConfig()) : + rapidXmmGmm(xmmToolConfig cfg = xmmToolConfig()) : + xmmStaticTool<xmm::GMM, xmm::GMM>(cfg, false) {} + // ~xmmGmmTool() {} + // ~GMM() {} + ~rapidXmmGmm() {} + + std::vector<double> run(const std::vector<double>& inputVector); +}; + +/** + * @brief Static regression using Gaussian Mixture Models + */ +// class xmmGmrTool : public xmmStaticTool<xmm::GMM, xmm::GMM> { +// class GMR : public xmmStaticTool<xmm::GMM, xmm::GMM> { +class rapidXmmGmr : public xmmStaticTool<xmm::GMM, xmm::GMM> { +public: + // xmmGmrTool(xmmToolConfig cfg = xmmToolConfig()) : + // GMR(xmmToolConfig cfg = xmmToolConfig()) : + rapidXmmGmr(xmmToolConfig cfg = xmmToolConfig()) : + xmmStaticTool<xmm::GMM, xmm::GMM>(cfg, true) {} + // ~xmmGmrTool() {} + // ~GMR() {} + ~rapidXmmGmr() {} + + std::vector<double> run(const std::vector<double>& inputVector); +}; + +/** + * @brief Temporal classification using Hierarchical Hidden Markov Models + */ +// class xmmHmmTool : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> { +// class HMM : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> { +class rapidXmmHmm : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> { +public: + // xmmHmmTool(xmmToolConfig cfg = xmmToolConfig()) : + // HMM(xmmToolConfig cfg = xmmToolConfig()) : + rapidXmmHmm(xmmToolConfig cfg = xmmToolConfig()) : + xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM>(cfg, false) {} + // ~xmmHmmTool() {} + // ~HMM() {} + ~rapidXmmHmm() {} + + std::vector<double> run(const std::vector<double>& inputVector); +}; + +/** + * @brief Temporal regression using Hierarchical Hidden Markov Models + */ +// class xmmHmrTool : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> { +// class HMR : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> { +class rapidXmmHmr : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> { +public: + // xmmHmrTool(xmmToolConfig cfg = xmmToolConfig()) : + // HMR(xmmToolConfig cfg = xmmToolConfig()) : + rapidXmmHmr(xmmToolConfig cfg = xmmToolConfig()) : + xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM>(cfg, true) {} + // ~xmmHmrTool() {} + // ~HMR() {} + ~rapidXmmHmr() {} + + std::vector<double> run(const std::vector<double>& inputVector); +}; + +#endif /* _RAPID_XMM_TOOLS_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/trainingData.cpp b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/trainingData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba209e7bdad03d4c1b48685f1a5fc65bf5ebc65f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/trainingData.cpp @@ -0,0 +1,207 @@ +/** + * @file trainingData.cpp + * @author Michael Zbyszynski + * @date 2 Feb 2017 + * @copyright Copyright © 2017 Goldsmiths. All rights reserved. + */ + +#include "trainingData.h" + +namespace rapidmix { + + trainingData::trainingData () { + currentId = 0; + targetPhrase = 0; + }; + + uint32_t trainingData::assignCurrentId() { + uint32_t returnVal = currentId; + ++currentId; + return returnVal; + } + + std::vector<trainingData::phrase>::iterator trainingData::createNewPhrase(std::string label) { + phrase tempPhrase = { assignCurrentId(), label }; + trainingSet.push_back(tempPhrase); + std::vector<trainingData::phrase>::iterator it = --trainingSet.end(); + return it; + }; + + uint32_t trainingData::startRecording() { + phrase tempPhrase = { assignCurrentId(), std::to_string(tempPhrase.uniqueId) }; //TODO: Is this label helpful? -MZ + trainingSet.push_back(tempPhrase); + targetPhrase = int(trainingSet.size() - 1); + return tempPhrase.uniqueId; + }; + + uint32_t trainingData::startRecording(const std::string &label) { + phrase tempPhrase = { assignCurrentId(), label }; + trainingSet.push_back(tempPhrase); + targetPhrase = int(trainingSet.size() - 1); + return tempPhrase.uniqueId; + + }; + + uint32_t trainingData::addElement(const std::vector<double> &input, const std::vector<double> &output) { + element newElement; + newElement.uniqueId = assignCurrentId(); + newElement.input = input; + newElement.output = output; + newElement.timeStamp = NULL; + trainingSet[targetPhrase].elements.push_back(newElement); + return newElement.uniqueId; + } + + uint32_t trainingData::addElement(const std::vector<double> &input) { + element newElement; + newElement.uniqueId = assignCurrentId(); + newElement.input = input; + newElement.timeStamp = NULL; + trainingSet[targetPhrase].elements.push_back(newElement); + return newElement.uniqueId; + } + + + void trainingData::stopRecording() { + //TODO: This doesn't do much. -MZ + } + + uint32_t trainingData::recordSingleElement(const std::string &label, const std::vector<double> &input) { + startRecording(label); + int returnId = addElement(input); + stopRecording(); + return returnId; + }; + + uint32_t trainingData::recordSingleElement(const std::vector<double> &input, const std::vector<double> &output) { + startRecording(); + int returnId = addElement(input, output); + stopRecording(); + return returnId; + }; + + uint32_t trainingData::recordSingleElement(const std::string &label, const std::vector<double> &input, const std::vector<double> &output) { + startRecording(label); + int returnId = addElement(input, output); + stopRecording(); + return returnId; + }; + + std::vector<std::string> trainingData::getColumnNames() { + return trainingSet[targetPhrase].columnNames; + } + + void trainingData::setColumnNames(const std::vector<std::string> &column_names) { + trainingSet[targetPhrase].columnNames = column_names; + } + + Json::Value trainingData::parse2json() { + Json::Value root; + Json::Value metadata; + Json::Value trainingSetJSON; + + metadata["creator"] = "RAPID-MIX API C++"; + metadata["version"] = RAPIDMIX_VERSION; + + //Go through all the phrases + for (int i = 0; i < trainingSet.size(); ++i) { + Json::Value thisPhrase; + thisPhrase.append(trainingSet[i].uniqueId); + thisPhrase.append(trainingSet[i].label); + + Json::Value column_names; + for (int j = 0; j < trainingSet[i].columnNames.size(); ++j) { + column_names.append(trainingSet[i].columnNames[j]); + } + thisPhrase.append(column_names); + + Json::Value elements; + for (int j = 0; j < trainingSet[i].elements.size(); ++j) { + Json::Value singleElement; + + Json::Value elementInput; + for (int k = 0; k < trainingSet[i].elements[j].input.size(); ++k) { + elementInput.append(trainingSet[i].elements[j].input[k]); + } + singleElement.append(elementInput); + + Json::Value elementOutput; + for (int k = 0; k < trainingSet[i].elements[j].output.size(); ++k) { + elementOutput.append(trainingSet[i].elements[j].output[k]); + } + singleElement.append(elementOutput); + + singleElement.append(trainingSet[i].elements[j].timeStamp); + elements.append(singleElement); + } + thisPhrase.append(elements); + + trainingSetJSON.append(thisPhrase); + } + + root["metadata"] = metadata; + root["trainingSet"] = trainingSetJSON; + return root; + } + + std::string trainingData::getJSON() { + Json::Value root = parse2json(); + return root.toStyledString(); + } + + void trainingData::writeJSON(const std::string &filepath) { + Json::Value root = parse2json(); + std::ofstream jsonOut; + jsonOut.open (filepath); + Json::StyledStreamWriter writer; + writer.write(jsonOut, root); + jsonOut.close(); + + } + + void trainingData::json2trainingSet(const Json::Value &root) { + trainingSet = {}; + for (const Json::Value& jsonPhrase : root["trainingSet"]) { + + phrase tempPhrase = { jsonPhrase[0].asUInt(), jsonPhrase[1].asString() }; + + for (int i = 0; i < jsonPhrase[2].size(); ++i) { + tempPhrase.columnNames.push_back(jsonPhrase[2][i].asString()); + } + + for (int i = 0; i < jsonPhrase[3].size(); ++i) { + element tempElement; + for (int j = 0; j < jsonPhrase[3][i][0].size(); ++j) { + tempElement.input.push_back(jsonPhrase[3][i][0][j].asDouble()); + } + for (int j = 0; j < jsonPhrase[3][i][1].size(); ++j) { + tempElement.output.push_back(jsonPhrase[3][i][1][j].asDouble()); + } + tempElement.timeStamp = jsonPhrase[3][i][2].asDouble(); + + tempPhrase.elements.push_back(tempElement); + } + trainingSet.push_back(tempPhrase); + } + } + + bool trainingData::putJSON(const std::string &jsonMessage) { + Json::Value parsedFromString; + Json::Reader reader; + bool parsingSuccessful = reader.parse(jsonMessage, parsedFromString); + if (parsingSuccessful) + { + json2trainingSet(parsedFromString); + } + return parsingSuccessful; + } + + bool trainingData::readJSON(const std::string &filepath) { + Json::Value root; + std::ifstream file(filepath); + file >> root; + json2trainingSet(root); + return true; //TODO: check something first + } + +} diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/trainingData.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/trainingData.h new file mode 100644 index 0000000000000000000000000000000000000000..67f4a67126a4b20e23aa653022319c51c60e3816 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/machineLearning/trainingData.h @@ -0,0 +1,114 @@ +/** + * @file trainingData.h + * @author Michael Zbyszynski + * @date 2 Feb 2017 + * @copyright + * Copyright © 2017 Goldsmiths. All rights reserved. + * + * @ingroup machinelearning + */ + +#ifndef trainingData_h +#define trainingData_h + +#include <vector> +#include <string> +#include <unordered_map> + +#include "../rapidmix.h" +#include "json.h" + +namespace rapidmix { + + /** This is used by both NN and KNN models for training */ + class trainingData { + + public: + + trainingData(); + + struct element{ + uint32_t uniqueId; //MZ: Does this scope of this id need to extend beyond this instantiation? + std::vector<double> input; + std::vector<double> output; + double timeStamp; + }; + + struct phrase { + uint32_t uniqueId; + std::string label; //TODO: Need to work this with templates + std::vector<std::string> columnNames; //equal to the number of inputs + std::vector<element> elements; + + + //TODO: This is just a design idea right now. + void addElement (const std::vector<double> &input, const std::vector<double> &output) + { + element tempElement; +// tempElement.uniqueId = assignCurrentId(); //TODO: how to do this? Do we need this? + tempElement.input = input; + tempElement.output = output; + tempElement.timeStamp = NULL; + this->elements.push_back(tempElement); + } + }; + + std::vector<phrase> trainingSet; + + //TODO: Deleting phrases (last or by label) + //Design ideas to make phrase building stateless: + std::vector<phrase>::iterator createNewPhrase(); //??? Do we need this? + std::vector<phrase>::iterator createNewPhrase(std::string label); + + /** Create a new phrase that can be recorded into. Returns phrase id */ + uint32_t startRecording(); //FIXME: this should go away. -MZ + + /** Create new phrase, with a label, that can be recorded into. Returns phrase id */ + uint32_t startRecording(const std::string &label); + + /** Add an element with input and output to the phrase that is recording, + or to the default phrase if recording is stopped. Returns phrase id. */ + uint32_t addElement(const std::vector<double> &input, const std::vector<double> &output); + + /** Add an element with just input to the phrase that is recording, + or to the default phrase if recording is stopped. Returns phrase id. */ + uint32_t addElement(const std::vector<double> &input); + + void stopRecording(); + + /** Create a phrase with a single element that has a label and input. Returns phrase id. */ + uint32_t recordSingleElement(const std::string &label, const std::vector<double> &input); + + /** Create a phrase with a single element that has input, and output. Returns phrase id. */ + uint32_t recordSingleElement(const std::vector<double> &input, const std::vector<double> &output); + + /** Create a phrase with a single element that has a label, input, and output. Returns phrase id. */ + uint32_t recordSingleElement(const std::string &label, const std::vector<double> &input, const std::vector<double> &output); + + std::vector<std::string> getColumnNames(); + void setColumnNames(const std::vector<std::string> &columnNames); + + /** Get a JSON representation of the data set in the form of a styled string */ + std::string getJSON(); + /** Write a JSON version of the training set to specified file path */ + void writeJSON(const std::string &filepath); + /** populate a data set with string. See getJSON() */ + bool putJSON(const std::string &jsonMessage); + /** read a JSON file at file path and build a training set from it */ + bool readJSON(const std::string &filepath); + + private: + int targetPhrase; + uint32_t currentId; + + //* Returns and increments current id */ + uint32_t assignCurrentId(); + + Json::Value parse2json(); + void json2trainingSet(const Json::Value &newTrainingData); + + }; + +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/rapidmix.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/rapidmix.h new file mode 100644 index 0000000000000000000000000000000000000000..fa3e13e5b699fd18d683c326f34ca3c45d142682 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/rapidmix.h @@ -0,0 +1,48 @@ +/** + * @file rapidmix.h + * @author Michael Zbyszynski + * @date 12 Jan 2017 + * + * @copyright + * Copyright © 2017 Goldsmiths. All rights reserved. + */ + +/** + * @mainpage RAPID-MIX API + * + * @section Introduction + * + * Hello, API ! <br> + * All the classes, functions and structs documented here belong to the + * <code>rapidmix</code> namespace. + * + * @section Examples + * @subsection Simple classification + * TODO + */ + +///////////////////////////////////////////////////////////////////////////// +// ______ _ _ ___ ____ ___ ______ _____ // +// | ___ \ (_) | | | \/ (_) / _ \ | ___ \_ _| // +// | |_/ /__ _ _ __ _ __| |______| . . |___ __ / /_\ \| |_/ / | | // +// | // _` | '_ \| |/ _` |______| |\/| | \ \/ / | _ || __/ | | // +// | |\ \ (_| | |_) | | (_| | | | | | |> < | | | || | _| |_ // +// \_| \_\__,_| .__/|_|\__,_| \_| |_/_/_/\_\ \_| |_/\_| \___/ // +// | | // +// |_| // +///////////////////////////////////////////////////////////////////////////// + +#ifndef rapidmix_h +#define rapidmix_h + +#define RAPIDMIX_VERSION_MAJOR 2 +#define RAPIDMIX_VERSION_MINOR 2 +#define RAPIDMIX_VERSION_PATCH 0 +#define RAPIDMIX_VERSION "2.2.0" +#define RAPIDMIX_REVISION "27-SEPTEMBER-2017" + +#include "machineLearning/machineLearning.h" +#include "machineLearning/trainingData.h" +#include "signalProcessing/signalProcessing.h" + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoHost.cpp b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoHost.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6663da43170182caff13ab52db0a34fca1c158fa --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoHost.cpp @@ -0,0 +1,764 @@ +#include "rapidPiPoHost.h" +#include <iostream> +#include <fstream> + +//=========================== H O S T === U T I L S ==========================// + +/* +static const unsigned int maxWordLen = 256; + +static bool getPiPoInstanceAndAttrName(const char *attrName, + char *instanceName, + char *pipoAttrName) +{ + const char *dot = std::strrchr(attrName, '.'); + + if (dot != NULL) + { + long pipoAttrNameLen = dot - attrName; + std::strcpy(pipoAttrName, dot + 1); + + if (pipoAttrNameLen > maxWordLen) + { + pipoAttrNameLen = maxWordLen; + } + + std::strncpy(instanceName, attrName, pipoAttrNameLen); + instanceName[pipoAttrNameLen] = '\0'; + + return true; + } + + return false; +} +//*/ + + +static void fromPiPoStreamAttributes(PiPoStreamAttributes &src, + pipoStreamAttributes &dst) +{ + unsigned int numCols = src.dims[0]; + unsigned int numLabels = src.numLabels; + + if (numLabels > PIPO_MAX_LABELS) { + numLabels = PIPO_MAX_LABELS; + } + + if (numLabels > numCols) { + numLabels = numCols; + } + + dst.hasTimeTags = src.hasTimeTags; + + if (src.rate <= MIN_PIPO_SAMPLERATE) { + dst.rate = MIN_PIPO_SAMPLERATE; + } else if (src.rate >= MAX_PIPO_SAMPLERATE) { + dst.rate = MAX_PIPO_SAMPLERATE; + } else { + dst.rate = src.rate; + } + + dst.rate = src.rate; + dst.offset = src.offset; + dst.width = src.dims[0]; + dst.height = src.dims[1]; + + dst.labels = std::vector<std::string>(); + + for (unsigned int i = 0; i < numLabels; ++i) + { + dst.labels.push_back(std::string(src.labels[i])); + } + + dst.hasVarSize = src.hasVarSize; + dst.domain = src.domain; + dst.maxFrames = src.maxFrames; +} + + +static void toPiPoStreamAttributes(pipoStreamAttributes &src, + PiPoStreamAttributes &dst) +{ + const char *labs[src.labels.size()]; + + for (unsigned int i = 0; i < src.labels.size(); ++i) + { + labs[i] = src.labels[i].c_str(); + } + + dst = PiPoStreamAttributes( + src.hasTimeTags, + src.rate, + src.offset, + src.width, + src.height, + &labs[0], + src.hasVarSize, + src.domain, + src.maxFrames + ); +} + +//========================= H O S T === M E T H O D S ========================// + +PiPoHost::PiPoHost() : +inputStreamAttrs(PIPO_MAX_LABELS), +outputStreamAttrs(PIPO_MAX_LABELS) +{ + PiPoCollection::init(); + this->out = new PiPoOut(this); + this->graph = nullptr; +} + +PiPoHost::~PiPoHost() +{ + if (this->graph != nullptr) + { + delete this->graph; + } + + delete this->out; +} + +bool +PiPoHost::setGraph(std::string name) +{ + if (this->graph != nullptr) + { + delete this->graph; + } + + this->graph = PiPoCollection::create(name); + + if (this->graph != NULL) + { + this->graphName = name; + this->graph->setReceiver((PiPo *)this->out); + return true; + } + + this->graph = nullptr; + this->graphName = "undefined"; + return false; +} + +void +PiPoHost::clearGraph() +{ + if (this->graph != nullptr) + { + delete this->graph; + this->graph = nullptr; + } +} + + +void +PiPoHost::onNewFrameOut(double time, std::vector<PiPoValue> &frame) +{ + std::cout << time << std::endl; + std::cout << "please override this method" << std::endl; +} + +std::vector<PiPoValue> +PiPoHost::getLastFrameOut() +{ + return this->out->getLastFrame(); +} + + + +int +PiPoHost::setInputStreamAttributes(pipoStreamAttributes &sa, bool propagate) +{ + toPiPoStreamAttributes(sa, inputStreamAttrs); + + if (propagate) + { + return this->propagateInputStreamAttributes(); + } + + return 0; +} + +pipoStreamAttributes +PiPoHost::getOutputStreamAttributes() +{ + pipoStreamAttributes sa; + fromPiPoStreamAttributes(this->outputStreamAttrs, sa); + return sa; +} + +int +PiPoHost::frames(double time, double weight, PiPoValue *values, unsigned int size, + unsigned int num) +{ + return this->graph->frames(time, weight, values, size, num); +} + + + +// bool +// setAttr(const std::string &attrName, bool value) +// { + +// } + +// bool +// setAttr(const std::string &attrName, int value) +// { + +// } + +bool +PiPoHost::setAttr(const std::string &attrName, double value) +{ + PiPo::Attr *attr = this->graph->getAttr(attrName.c_str()); + + if (attr != NULL) + { + int iAttr = attr->getIndex(); + return this->graph->setAttr(iAttr, value); + } + + return false; +} + +bool +PiPoHost::setAttr(const std::string &attrName, const std::vector<double> &values) +{ + PiPo::Attr *attr = this->graph->getAttr(attrName.c_str()); + + if (attr != NULL) + { + int iAttr = attr->getIndex(); + double vals[values.size()]; + unsigned int i = 0; + + for (auto &value : values) + { + vals[i] = value; + i++; + } + + return this->graph->setAttr(iAttr, &vals[0], static_cast<unsigned int>(values.size())); + } + + return false; +} + +bool +PiPoHost::setAttr(const std::string &attrName, const std::string &value) // for enums +{ + PiPo::Attr *attr = this->graph->getAttr(attrName.c_str()); + + if (attr != NULL) + { + // int iAttr = attr->getIndex(); + PiPo::Type type = attr->getType(); + + if (type == PiPo::Type::Enum) + { + std::vector<const char *> *list = attr->getEnumList(); + + for (int i = 0; i < list->size(); i++) + { + if (strcmp(list->at(i), value.c_str()) == 0) + { + attr->set(0, i); + return true; + } + } + } + } + + return false; +} + +std::vector<std::string> +PiPoHost::getAttrNames() +{ + std::vector<std::string> res; + + for (unsigned int i = 0; i < this->graph->getNumAttrs(); ++i) + { + res.push_back(this->graph->getAttr(i)->getName()); + } + + return res; +} + +double +PiPoHost::getDoubleAttr(const std::string &attrName) +{ + PiPo::Attr *attr = this->graph->getAttr(attrName.c_str()); + + if (attr != NULL) { + // int iAttr = attr->getIndex(); + PiPo::Type type = attr->getType(); + + if (type == PiPo::Type::Double) { + return attr->getDbl(0); + } + } + + return 0; +} + +std::vector<double> +PiPoHost::getDoubleArrayAttr(const std::string &attrName) +{ + std::vector<double> res; + PiPo::Attr *attr = this->graph->getAttr(attrName.c_str()); + + if (attr != NULL) { + // int iAttr = attr->getIndex(); + PiPo::Type type = attr->getType(); + + if (type == PiPo::Type::Double) { + for (int i = 0; i < attr->getSize(); ++i) { + res.push_back(attr->getDbl(i)); + } + } + } + + return res; +} + +std::string +PiPoHost::getEnumAttr(const std::string &attrName) +{ + PiPo::Attr *attr = this->graph->getAttr(attrName.c_str()); + + if (attr != NULL) { + // int iAttr = attr->getIndex(); + PiPo::Type type = attr->getType(); + + if (type == PiPo::Type::Enum) { + return attr->getStr(0); + } + } + + return ""; +} + +//============================= JSON FORMATTING ==============================// + +std::string +PiPoHost::getJSON() +{ + Json::Value result = toJSON(); + return result.toStyledString(); +} + +void +PiPoHost::writeJSON(const std::string &filepath) +{ + Json::Value root = toJSON(); + std::ofstream jsonOut; + jsonOut.open (filepath); + Json::StyledStreamWriter writer; + writer.write(jsonOut, root); + jsonOut.close(); +} + +bool +PiPoHost::putJSON(const std::string &jsonMessage) +{ + Json::Value parsedFromString; + Json::Reader reader; + bool parsingSuccessful = reader.parse(jsonMessage, parsedFromString); + return (parsingSuccessful && fromJSON(parsedFromString)); +} + +bool +PiPoHost::readJSON(const std::string &filepath) +{ + Json::Value root; + std::ifstream file(filepath); + file >> root; + return fromJSON(root); +} + +//======================== PROTECTED HOST METHODS ============================// + +Json::Value +PiPoHost::toJSON() +{ + Json::Value root; + Json::Value metadata; + Json::Value pipodata; + + metadata["creator"] = "RAPID-MIX API";// C++"; + metadata["version"] = "v0.1.1"; //TODO: This should be a macro someplace + metadata["family"] = "pipo"; + + root["metadata"] = metadata; + + pipodata["description"] = this->graphName; + + Json::Value inputStream; + inputStream["hasTimeTags"] = inputStreamAttrs.hasTimeTags; + inputStream["rate"] = inputStreamAttrs.rate; + inputStream["offset"] = inputStreamAttrs.offset; + inputStream["width"] = inputStreamAttrs.dims[0]; + inputStream["height"] = inputStreamAttrs.dims[1]; + inputStream["labels"] = inputStreamAttrs.labels; + inputStream["hasVarSize"] = inputStreamAttrs.hasVarSize; + inputStream["domain"] = inputStreamAttrs.domain; + inputStream["maxFrames"] = inputStreamAttrs.maxFrames; + + Json::Value outputStream; + outputStream["hasTimeTags"] = outputStreamAttrs.hasTimeTags; + outputStream["rate"] = outputStreamAttrs.rate; + outputStream["offset"] = outputStreamAttrs.offset; + outputStream["width"] = outputStreamAttrs.dims[0]; + outputStream["height"] = outputStreamAttrs.dims[1]; + outputStream["labels"] = outputStreamAttrs.labels; + outputStream["hasVarSize"] = outputStreamAttrs.hasVarSize; + outputStream["domain"] = outputStreamAttrs.domain; + outputStream["maxFrames"] = outputStreamAttrs.maxFrames; + + Json::Value streams; + streams["input"] = inputStream; + streams["output"] = outputStream; + + pipodata["streamAttributes"] = streams; + + Json::Value params; + int n = this->graph->getNumAttrs(); + params.resize(static_cast<Json::ArrayIndex>(n)); + + for (unsigned int i = 0; i < n; ++i) + { + Json::Value param; + PiPo::Attr *a = this->graph->getAttr(i); + param["name"] = a->getName(); + param["value"] = a->getDbl(0); + params[i] = param; + } + + pipodata["parameters"] = params; + + root["pipodata"] = pipodata; + + return root; +} + +bool +PiPoHost::fromJSON(Json::Value &jv) +{ + if (jv["metadata"]["family"].asString().compare("pipo") == 0 && + jv["pipodata"].size() > 0) { + + this->setGraph(jv["pipodata"]["description"].asString()); + + Json::Value inputStream = jv["pipodata"]["streamAttributes"]["input"]; + // setInputStreamAttributes( + // inputStream["hasTimeTags"].getDbl()//, + // //... + // ); + return true; + } + + return false; +} + +//========================= PRIVATE HOST METHODS =============================// + +int +PiPoHost::propagateInputStreamAttributes() +{ + if (this->graph != nullptr) + { + return this->graph->streamAttributes(this->inputStreamAttrs.hasTimeTags, + this->inputStreamAttrs.rate, + this->inputStreamAttrs.offset, + this->inputStreamAttrs.dims[0], + this->inputStreamAttrs.dims[1], + this->inputStreamAttrs.labels, + this->inputStreamAttrs.hasVarSize, + this->inputStreamAttrs.domain, + this->inputStreamAttrs.maxFrames); + } + + return 0; +} + +void +PiPoHost::setOutputAttributes(bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int height, + const char **labels, bool hasVarSize, + double domain, unsigned int maxFrames) { + if (labels != NULL) { + int numLabels = width; + + if (numLabels > PIPO_MAX_LABELS) { + numLabels = PIPO_MAX_LABELS; + } + + for (unsigned int i = 0; i < numLabels; i++) { + try { + this->outputStreamAttrs.labels[i] = labels[i]; + } catch(std::exception e) { + this->outputStreamAttrs.labels[i] = "unnamed"; + } + } + + this->outputStreamAttrs.numLabels = numLabels; + } else { + this->outputStreamAttrs.numLabels = 0; + } + + this->outputStreamAttrs.hasTimeTags = hasTimeTags; + this->outputStreamAttrs.rate = rate; + this->outputStreamAttrs.offset = offset; + this->outputStreamAttrs.dims[0] = width; + this->outputStreamAttrs.dims[1] = height; + this->outputStreamAttrs.hasVarSize = hasVarSize; + this->outputStreamAttrs.domain = domain; + this->outputStreamAttrs.maxFrames = maxFrames; +} + + + +// void +// PiPoHost::streamAttributesChanged(PiPo *pipo, PiPo::Attr *attr) { +// this->propagateInputAttributes(); +// } + +// void +// PiPoHost::signalError(PiPo *pipo, std::string errorMsg) { +// // todo +// } + +// void +// PiPoHost::signalWarning(PiPo *pipo, std::string warningMsg) { +// // todo +// } + +//--------------------- INPUT STREAM ATTRIBUTES SETTERS ----------------------// + +/* +void +PiPoHost::setInputHasTimeTags(bool hasTimeTags, bool propagate) { + this->inputStreamAttrs.hasTimeTags = hasTimeTags; + + if (propagate) { + this->propagateInputAttributes(); + } +} + +#define MIN_PIPO_SAMPLERATE (1.0 / 31536000000.0) // once a year +#define MAX_PIPO_SAMPLERATE (96000000000.0) + +void +PiPoHost::setInputFrameRate(double rate, bool propagate) { + if (rate <= MIN_PIPO_SAMPLERATE) { + this->inputStreamAttrs.rate = MIN_PIPO_SAMPLERATE; + } else if (rate >= MAX_PIPO_SAMPLERATE) { + this->inputStreamAttrs.rate = MAX_PIPO_SAMPLERATE; + } else { + this->inputStreamAttrs.rate = rate; + } + + if (propagate) { + this->propagateInputAttributes(); + } +} + +void +PiPoHost::setInputFrameOffset(double offset, bool propagate) { + this->inputStreamAttrs.offset = offset; + + if (propagate) { + this->propagateInputAttributes(); + } +} + +void +PiPoHost::setInputDims(int width, int height, bool propagate) { + this->inputStreamAttrs.dims[0] = width; + this->inputStreamAttrs.dims[1] = height; + + if (propagate) { + this->propagateInputAttributes(); + } +} + +void +PiPoHost::setInputLabels(const std::vector<std::string> &labels, bool propagate) { + const char *labs[labels.size()]; + + for (unsigned int i = 0; i < labels.size(); ++i) { + labs[i] = labels[i].c_str(); + } + + this->inputStreamAttrs.labels = &labs[0]; + + if (propagate) { + this->propagateInputAttributes(); + } +} + +void +PiPoHost::setInputHasVarSize(bool hasVarSize, bool propagate) { + this->inputStreamAttrs.hasVarSize = hasVarSize; + + if (propagate) { + this->propagateInputAttributes(); + } +} + +void +PiPoHost::setInputDomain(double domain, bool propagate) { + this->inputStreamAttrs.domain = domain; + + if (propagate) { + this->propagateInputAttributes(); + } +} + +void +PiPoHost::setInputMaxFrames(int maxFrames, bool propagate) { + this->inputStreamAttrs.maxFrames = maxFrames; + + if (propagate) { + this->propagateInputAttributes(); + } +} +//*/ + +//--------------------- INPUT STREAM ATTRIBUTES GETTERS ----------------------// + +/* +bool +PiPoHost::getInputHasTimeTags() { + return this->inputStreamAttrs.hasTimeTags; +} + +double +PiPoHost::getInputFrameRate() { + return this->inputStreamAttrs.rate; +} + +double +PiPoHost::getInputFrameOffset() { + return this->inputStreamAttrs.offset; +} + +void +PiPoHost::getInputDims(int &width, int &height) { + width = this->inputStreamAttrs.dims[0]; + height = this->inputStreamAttrs.dims[1]; +} + +void +PiPoHost::getInputLabels(std::vector<std::string> &labels) { + //for (unsigned int i = 0; i < ) +} + +bool +PiPoHost::getInputHasVarSize() { + return this->inputStreamAttrs.hasVarSize; +} + +double +PiPoHost::getInputDomain() { + return this->inputStreamAttrs.domain; +} + +int +PiPoHost::getInputMaxFrames() { + return this->inputStreamAttrs.maxFrames; +} +//*/ + +//--------------------- OUTPUT STREAM ATTRIBUTES GETTERS ---------------------// + +// void +// PiPoHost::setOutputAttributes(bool hasTimeTags, double rate, double offset, +// unsigned int width, unsigned int height, +// const char **labels, bool hasVarSize, +// double domain, unsigned int maxFrames) { +// if (labels != NULL) { +// int numLabels = width; + +// if (numLabels > PIPO_MAX_LABELS) { +// numLabels = PIPO_MAX_LABELS; +// } + +// for (unsigned int i = 0; i < numLabels; i++) { +// try { +// this->outputStreamAttrs.labels[i] = labels[i]; +// } catch(std::exception e) { +// this->outputStreamAttrs.labels[i] = "unnamed"; +// } +// } + +// this->outputStreamAttrs.numLabels = numLabels; +// } else { +// this->outputStreamAttrs.numLabels = 0; +// } + +// this->outputStreamAttrs.hasTimeTags = hasTimeTags; +// this->outputStreamAttrs.rate = rate; +// this->outputStreamAttrs.offset = offset; +// this->outputStreamAttrs.dims[0] = width; +// this->outputStreamAttrs.dims[1] = height; +// this->outputStreamAttrs.hasVarSize = hasVarSize; +// this->outputStreamAttrs.domain = domain; +// this->outputStreamAttrs.maxFrames = maxFrames; +// } + +/* +bool +PiPoHost::getOutputHasTimeTags() { + return this->outputStreamAttrs.hasTimeTags; +} + +double +PiPoHost::getOutputFrameRate() { + return this->outputStreamAttrs.rate; +} + +double +PiPoHost::getOutputFrameOffset() { + return this->outputStreamAttrs.offset; +} + +void +PiPoHost::getOutputDims(int &width, int &height) { + width = this->outputStreamAttrs.dims[0]; + height = this->outputStreamAttrs.dims[1]; +} + +void +PiPoHost::getOutputLabels(std::vector<std::string> &labels) { + labels.clear(); + + for (unsigned int i = 0; this->outputStreamAttrs.numLabels; ++i) { + + if (this->outputStreamAttrs.labels[i] != NULL) { + labels.push_back(std::string(this->outputStreamAttrs.labels[i])); + } else { + labels.push_back("unnamed"); + } + } +} + +bool +PiPoHost::getOutputHasVarSize() { + return this->outputStreamAttrs.hasVarSize; +} + +double +PiPoHost::getOutputDomain() { + return this->outputStreamAttrs.domain; +} + +int +PiPoHost::getOutputMaxFrames() { + return this->outputStreamAttrs.maxFrames; +} +//*/ diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoHost.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoHost.h new file mode 100644 index 0000000000000000000000000000000000000000..b898da3e1ed549f74d17818c5d70d4745fe48697 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoHost.h @@ -0,0 +1,249 @@ +#ifndef _RAPID_PIPO_HOST_H_ +#define _RAPID_PIPO_HOST_H_ + +#include "PiPo.h" +#include "PiPoHost.h" +#include "PiPoCollection.h" + +//#ifdef EXTERNAL_JSONCPP_PATH +#define EXTERNAL_JSONCPP_PATH "json.h" +#include EXTERNAL_JSONCPP_PATH +//#endif /* EXTERNAL_JSONCPP_PATH */ + +#define MIN_PIPO_SAMPLERATE (1.0 / 31536000000.0) /* once a year */ +#define MAX_PIPO_SAMPLERATE (96000000000.0) + +#define PIPO_OUT_RING_SIZE 2 + +struct pipoStreamAttributes { + pipoStreamAttributes() : // default parameters suited for audio + hasTimeTags(false), + rate(MIN_PIPO_SAMPLERATE), + offset(0), + width(1), + height(1), + labels({ "" }), + hasVarSize(false), + domain(0), + maxFrames(1) {} + + bool hasTimeTags; + double rate; + double offset; + unsigned int width; + unsigned int height; + std::vector<std::string> labels; + bool hasVarSize; + double domain; + unsigned int maxFrames; +}; + + +//class PiPoObserver; +class PiPoOut; + +//================================ H O S T ===================================// + +class PiPoHost : public PiPo::Parent { + friend class PiPoOut; + +private: + PiPo *graph; + std::string graphName; + PiPoOut *out; + // PiPoObserver *obs; + PiPoStreamAttributes inputStreamAttrs; + PiPoStreamAttributes outputStreamAttrs; + +public: + // PiPoHost(PiPoObserver *obs); + PiPoHost(); + ~PiPoHost(); + + // PiPoObserver *getObserver(); + + virtual bool setGraph(std::string name); + virtual void clearGraph(); + + // override this method when inheriting !!! + virtual void onNewFrameOut(double time, std::vector<PiPoValue> &frame); + virtual std::vector<PiPoValue> getLastFrameOut(); + + virtual int setInputStreamAttributes(pipoStreamAttributes &sa, bool propagate = true); + virtual pipoStreamAttributes getOutputStreamAttributes(); + + virtual int frames(double time, double weight, PiPoValue *values, unsigned int size, + unsigned int num); + + // virtual bool setAttr(const std::string &attrName, bool value); + // virtual bool setAttr(const std::string &attrName, int value); + virtual bool setAttr(const std::string &attrName, double value); + virtual bool setAttr(const std::string &attrName, const std::vector<double> &values); + virtual bool setAttr(const std::string &attrName, const std::string &value); // for enums + + // virtual const std::vector<std::string>& getAttrNames(); + // virtual bool isBoolAttr(const std::string &attrName); + // virtual bool isEnumAttr(const std::string &attrName); + // virtual bool isIntAttr(const std::string &attrName); + // virtual bool isIntArrayAttr(const std::string &attrName); + // virtual bool isFloatAttr(const std::string &attrName); + // virtual bool isFloatArrayAttr(const std::string &attrName); + // virtual bool isStringAttr(const std::string &attrName); + + virtual std::vector<std::string> getAttrNames(); + + virtual double getDoubleAttr(const std::string &attrName); + virtual std::vector<double> getDoubleArrayAttr(const std::string &attrName); + virtual std::string getEnumAttr(const std::string &attrName); + + /** Get a JSON representation of the model in the form of a styled string */ + virtual std::string getJSON(); + /** Write a JSON model description to specified file path */ + virtual void writeJSON(const std::string &filepath); + /** configure empty model with string. See getJSON() */ + virtual bool putJSON(const std::string &jsonMessage); + /** read a JSON file at file path and build a modelSet from it */ + virtual bool readJSON(const std::string &filepath); + + + // int streamAttributes(bool hasTimeTags, double rate, double offset, + // unsigned int width, unsigned int height, + // const std::vector<std::string> &labels, + // bool hasVarSize, double domain, unsigned int maxFrames, + // bool propagate = true); + + // void propagateInputAttributes(); + + + // void streamAttributesChanged(PiPo *pipo, PiPo::Attr *attr); + // void signalError(PiPo *pipo, std::string errorMsg); + // void signalWarning(PiPo *pipo, std::string warningMsg); + + /* + void setInputHasTimeTags(bool hasTimeTags, bool propagate = true); + void setInputFrameRate(double rate, bool propagate = true); + void setInputFrameOffset(double offset, bool propagate = true); + void setInputDims(int width, int height, bool propagate = true); + void setInputLabels(const std::vector<std::string> &labels, bool propagate = true); + void setInputHasVarSize(bool hasVarSize, bool propagate = true); + void setInputDomain(double domain, bool propagate = true); + void setInputMaxFrames(int maxFrames, bool propagate = true); + + bool getInputHasTimeTags(); + double getInputFrameRate(); + double getInputFrameOffset(); + void getInputDims(int &width, int &height); + void getInputLabels(std::vector<std::string> &labels); + bool getInputHasVarSize(); + double getInputDomain(); + int getInputMaxFrames(); + + bool getOutputHasTimeTags(); + double getOutputFrameRate(); + double getOutputFrameOffset(); + void getOutputDims(int &width, int &height); + void getOutputLabels(std::vector<std::string> &labels); + bool getOutputHasVarSize(); + double getOutputDomain(); + int getOutputMaxFrames(); + + // void setPiPoParam(PiPoParam *param); + //*/ +protected: + Json::Value toJSON(); + bool fromJSON(Json::Value &jv); + +private: + int propagateInputStreamAttributes(); + void setOutputAttributes(bool hasTimeTags, double rate, double offset, + unsigned int width, unsigned int height, + const char **labels, bool hasVarSize, + double domain, unsigned int maxFrames); + +}; + +//================================= PiPoOut ==================================// + + class PiPoOut : public PiPo { +private: + PiPoHost *host; + std::atomic<int> writeIndex, readIndex; + std::vector<std::vector<PiPoValue>> ringBuffer; + // std::function<void(std::vector<PiPoValue>, PiPoObserver *rpo)> frameCallback; + // std::function<void(std::vector<PiPoValue>)> simpleFrameCallback; + +public: + PiPoOut(PiPoHost *host) : + PiPo((PiPo::Parent *)host) { + this->host = host; + writeIndex = 0; + readIndex = 0; + ringBuffer.resize(PIPO_OUT_RING_SIZE); + } + + ~PiPoOut() {} + + int streamAttributes(bool hasTimeTags, + double rate, double offset, + unsigned int width, unsigned int height, + const char **labels, bool hasVarSize, + double domain, unsigned int maxFrames) { + + this->host->setOutputAttributes(hasTimeTags, rate, offset, width, height, + labels, hasVarSize, domain, maxFrames); + + for (int i = 0; i < PIPO_OUT_RING_SIZE; ++i) { + ringBuffer[i].resize(width * height); + } + + return 0; + } + + int frames(double time, double weight, float *values, + unsigned int size, unsigned int num) { + + if (num > 0) { + for (int i = 0; i < num; ++i) { + + for (int j = 0; j < size; ++j) { + ringBuffer[writeIndex][j] = values[i * size + j]; + } + + // atomic swap ? + writeIndex = 1 - writeIndex; + readIndex = 1 - writeIndex; + + this->host->onNewFrameOut(time, ringBuffer[readIndex]); + + if (writeIndex + 1 == PIPO_OUT_RING_SIZE) { + writeIndex = 0; + } else { + writeIndex++; + } + } + } + + return 0; + } + + //void setFrameCallback(std::function<void(std::vector<PiPoValue>, + // PiPoObserver *obs)> f) { + // frameCallback = f; + //} + + // void setSimpleFrameCallback(std::function<void(std::vector<PiPoValue>)> f) { + // simpleFrameCallback = f; + // } + + std::vector<PiPoValue> getLastFrame() { + std::vector<PiPoValue> f; + + if (readIndex > -1) { + f = ringBuffer[readIndex]; + } + + return f; + } +}; + +#endif /* _RAPID_PIPO_HOST_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoTools.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoTools.h new file mode 100644 index 0000000000000000000000000000000000000000..d9a2e0efbe555a74e1d9cb032c4b3ec181032d16 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/rapidPiPoTools/rapidPiPoTools.h @@ -0,0 +1,9 @@ +#ifndef _RAPID_PIPO_TOOLS_H_ +#define _RAPID_PIPO_TOOLS_H_ + +#include "rapidPiPoHost.h" + +typedef PiPoHost pipoHost; +typedef pipoStreamAttributes pipoStreamAttributes; + +# endif /* _RAPID_PIPO_TOOLS_H_ */ diff --git a/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/signalProcessing.h b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/signalProcessing.h new file mode 100644 index 0000000000000000000000000000000000000000..4bbbdbd2ccf4682c96725a9d89793b8e83b9463b --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapid-mix/signalProcessing/signalProcessing.h @@ -0,0 +1,36 @@ +/** + * @file signalProcessing.h + * @author Michael Zbyszynski + * @date 6 Feb 2017 + * @copyright + * Copyright © 2017 Goldsmiths. All rights reserved. + * + * @ingroup signalprocessing + */ + +#ifndef signalProcessing_h +#define signalProcessing_h + +#include "rapidMix.h" +//#include "maximilian.h" +//#include "maxim.h" +#include "rapidStream.h" +#include "rapidPiPoTools.h" + +namespace rapidmix { + + /* + * Wrapper for signalProcessing modules, currently a collection of typedefs + */ + + //typedef maxiFFT FFT; + //typedef maxiMFCC MFCC; + typedef rapidStream<double> rapidStream; + + typedef pipoHost pipoHost; + typedef pipoStreamAttributes pipoStreamAttributes; + + +} + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h b/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h new file mode 100644 index 0000000000000000000000000000000000000000..c0142495f964951f8abc07c0b967902ed5e26463 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h @@ -0,0 +1,145 @@ +// +// BitalinoThread.h +// Bitalino +// +// Created by James on 19/11/2017. +// +// + +#ifndef BitalinoThread_h +#define BitalinoThread_h + +#include <stdio.h> +#include "ThreadedProcess.h" +#include "RingBuffer.hpp" +#include "bitalino.h" + +class BitalinoThread : public ThreadedProcess { +public: + RingBuffer<BITalino::Frame> data; // The data gathered in the main thread, safely accessable from outside + + BitalinoThread ( void ) : ThreadedProcess () + { + connected.store(false); + recording.store(false); + tries.store(0); + deviceName = "/dev/cu.BITalino-DevB"; // Debug init (Mac OS virt. serial over bt) + } + + ~BitalinoThread ( void ) + { + } + + void setup ( std::string deviceName, uint64_t bufferSize, + uint16_t sampleRate, std::vector<int32_t> channels, + uint16_t frameCount=100 ) + { + this->deviceName = deviceName; + this->sampleRate = sampleRate; + this->channels = channels; + frameBuffer.resize(frameCount); + pollTestBuffer.resize(1); + data.setup(bufferSize); + } + + void setRecording ( bool v ) + { // Allow data to be pushed in to the ringbuffer + recording.store(v); + } + + bool isRecording ( void ) const + { + return recording.load(); + } + + bool isConnected ( void ) const + { + return connected.load(); + } + + uint32_t getConnectionTries( void ) const + { + return tries.load(); + } + +protected: + void mainThreadCallback ( void ) + { + try { + switch (threadState) + { + case SEARCHING_FOR_DEVICE: + ++currentTries; + tries.store(currentTries); + if (!dev) + dev = new BITalino(deviceName.c_str()); + dev->start(sampleRate, channels); + threadState = IDLE_BUT_CONNECTED; + connected.store(true); + currentTries = 0; + break; + case IDLE_BUT_CONNECTED: + if (recording.load()) + { + threadState = RECORDING_DATA; + } else { + dev->read(pollTestBuffer); // Poll small data to check if alive + usleep(100000); // Wait 100 ms + } + break; + case RECORDING_DATA: + if (!recording.load()) + { + threadState = IDLE_BUT_CONNECTED; + } else { + dev->read(frameBuffer); + if (data.items_available_for_write() >= frameBuffer.size()) + data.push(&frameBuffer[0], frameBuffer.size()); + // Else skipped frame... notify? + } + break; + default: + break; + } + usleep(100); + } catch (BITalino::Exception &e) { + // printf("BITalino exception: %s\n", e.getDescription()); + // TODO: check which exact exception is communication lost etc. + threadState = SEARCHING_FOR_DEVICE; + connected.store(false); + if (dev) + { + delete dev; + dev = nullptr; + } + usleep(500000); // 500ms Timeout before trying to reconnect + } + } + + std::atomic<bool> connected; + std::atomic<bool> recording; + std::string deviceName; + + BITalino* dev = nullptr; + uint16_t sampleRate = 1000; + std::vector<int32_t> channels; + + std::atomic<uint32_t> tries; + uint32_t currentTries = 0; + +private: + enum State { + SEARCHING_FOR_DEVICE, + IDLE_BUT_CONNECTED, + RECORDING_DATA + }; + + State threadState = SEARCHING_FOR_DEVICE; + + BITalino::VFrame frameBuffer; + BITalino::VFrame pollTestBuffer; +}; + + + +#endif /* BitalinoThread_h */ diff --git a/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e77ca250e02fe0e188ecb5793b413046b4b14673 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp @@ -0,0 +1,138 @@ +// +// RapidBitalino.cpp +// Bitalino +// +// Created by James on 20/11/2017. +// +// + +#include "RapidBitalino.h" + +RapidBitalino::RapidBitalino ( void ) +{ +} + +RapidBitalino::~RapidBitalino ( void ) +{ +} + +void RapidBitalino::clearTrainingData ( void ) +{ + // Clear the training set + (*currentPhrase).elements.clear(); + printf("Cleared training data\n"); +} + +void RapidBitalino::recordTrainingData( uint32_t samplesToCollect, double output ) +{ + this->samplesToCollect = samplesToCollect; + gatheringTrainingData = true; + bitalinoThread.data.reset(); // Reset read/write pointers + currentTrainingOutput = { output }; + printf("Recoriding training input for output: %f\n", output); +} + +void RapidBitalino::setup ( void ) +{ + // Get a reference to a new phrase which stores our trainingData + currentPhrase = trainingData.createNewPhrase("BITalino"); + // Set threaded train callback: (not sync) + rapidMixThread.threadedTrainCallback = [&] (selectedTraining* t ) + { + if (trainingData.trainingSet.size() > 0) + t->train(trainingData); + }; + // Set callback for when model is done training (sync) + rapidMixThread.doneTrainingCallback = [&] ( void ) + { + trainingText = "New Model Trained"; + printf("New Model Trained\n"); + }; + + // Set up the bitalino + bitalinoThread.setup("/dev/cu.BITalino-DevB", 2000, + 1000, {0, 1, 2, 3, 4, 5}, + 100); + // Start the bitalino's thread (and allow it to start searching for the device) + bitalinoThread.startThread(); + // Start receiving data as soon as it's connected + bitalinoThread.setRecording(true); + // Initialize with 0, 0 + bitalinoProcessedOutput = { 0.0, 0.0 }; + // Init FFT + fft.setup(128, 32, 32); +} + +bool RapidBitalino::processBitalinoOutput(BITalino::Frame& frame) +{ + std::vector<double> output; + double newVal = static_cast<float>(frame.analog[0]); + + discreteVal -= discreteVal / N; + discreteVal += newVal / N; + discreteValCalibrated = newVal - discreteVal; + + testCheapRMSdiscrete -= testCheapRMSdiscrete / M; + testCheapRMSdiscrete += (discreteValCalibrated*discreteValCalibrated) / M; + //bitalinoProcessedOutput = { sqrt(testCheapRMSdiscrete) }; + + if (fft.process(discreteValCalibrated)) + { + bitalinoProcessedOutput = { fft.spectralCentroid(), sqrt(testCheapRMSdiscrete) }; + + return true; + } + return false; +} + +void RapidBitalino::update ( void ) +{ // TODO: move this to its own thread and create communications between ofx and this so it doesn't block ofx + rapidMixThread.update(); + + uint32_t items = bitalinoThread.data.items_available_for_read(); + BITalino::Frame data[items]; + bitalinoThread.data.pop(data, items); + //double output; + + for (uint32_t i = 0; i < items; ++i) + { + if (processBitalinoOutput(data[i])) + { + tOutput = rapidMixThread.model->run(bitalinoProcessedOutput)[0]; + printf("Input = %f, %f, Output = %f\n",bitalinoProcessedOutput[0],bitalinoProcessedOutput[1], tOutput); + + if (gatheringTrainingData) + { + if (samplesToCollect > 0) + { + (*currentPhrase).addElement(bitalinoProcessedOutput, currentTrainingOutput); + --samplesToCollect; + } else { + gatheringTrainingData = false; + rapidMixThread.train(); // Start training process in its thread + } + } + } + } +} + +void RapidBitalino::draw ( void ) +{ + // Todo, draw some trivial debug interface items + // ie: + /* + - BITalino isConnected () + - BITalino isRecording () // if receiving data ? + - RapidMixThread isTraining () + - input and output values + */ + ofDrawBox(ofVec2f(400,(tOutput/4)*600), 50); +} + +void RapidBitalino::stop ( void ) +{ + rapidMixThread.stopThread(); + bitalinoThread.stopThread(); +} + + diff --git a/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h new file mode 100644 index 0000000000000000000000000000000000000000..eb1d77acb778786743204a452363212300f91094 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h @@ -0,0 +1,69 @@ +// +// RapidBitalino.h +// Bitalino +// +// Created by James on 20/11/2017. +// +// + +#ifndef RapidBitalino_h +#define RapidBitalino_h + +#include "ofMain.h" +#include "rapidmix.h" +#include "RapidMixThread.h" +#include "BitalinoThread.h" +#include "maxiFFT.h" + +typedef rapidmix::staticRegression selectedTraining; + +class RapidBitalino { +public: + RapidBitalino ( void ); + ~RapidBitalino ( void ); + + void clearTrainingData ( void ); + void recordTrainingData ( uint32_t numberOfSamplesToCollect, double output ); + void setup ( void ); + + void update ( void ); + void draw ( void ); + + void stop ( void ); + +private: + // Private member funcs + bool processBitalinoOutput(BITalino::Frame& frame); + + // Private variables + std::string trainingText = "idle"; + + // Rapid Mix stuff + rapidmix::trainingData trainingData; + std::vector<rapidmix::trainingData::phrase>::iterator currentPhrase; + + // My own stuff + uint32_t samplesToCollect; + std::vector<double> currentTrainingOutput; + + RapidMixThread<selectedTraining> rapidMixThread; + BitalinoThread bitalinoThread; + + bool gatheringTrainingData = false; + + // Processing the BITalino output + maxiFFT fft; + double discreteVal = 0; + double discreteValCalibrated = 0; + double N = 1000; + double M = 100; + + double testCheapRMSdiscrete = 0; + + double tOutput = 0.0; + + std::vector<double> bitalinoProcessedOutput; +}; + + +#endif /* RapidBitalino_h */ diff --git a/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h b/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h new file mode 100644 index 0000000000000000000000000000000000000000..d8efb2e42558e187f54db3521f1f6e5ca14b9135 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h @@ -0,0 +1,98 @@ +// +// RapidMixThread/h +// This implementation of rapidMix trains in a different thread and has a synchronized +// update process with your main thread, which triggers a (sync) callback on doneTraining. +// Allows you to train one model and keep using it while the next one trains, the new +// model will be swapped in sync with the thread the update is called in once it's done. +// Created by James on 19/11/2017. +// +// + +#ifndef RapidMixThread_h +#define RapidMixThread_h + +#include <algorithm> +#include <functional> +#include <unistd.h> // usleep +#include "ThreadedProcess.h" + +template <typename T> +class RapidMixThread : public ThreadedProcess +{ +public: + T* model = nullptr; // The model to be accessed + std::function<void ( void ) > doneTrainingCallback = nullptr; // CB on done training + std::function<void ( T* modelToBeTrained ) > threadedTrainCallback = nullptr; // Callback entry in train thread to pass training data and train the new model before it gets swapped in to place, note that any adjustments to the passed trainingdata or other non threadsafe elements at this point will result in undefined behavior + + RapidMixThread ( void ) : ThreadedProcess () + { + model = new T(); + training.store(false); + doneTraining.store(false); + startThread(); // Start training thread + } + + ~RapidMixThread ( void ) + { + stopThread(); + if (newModel) + delete newModel; + if (model) + delete model; + } + + void train ( void ) + { + if (!training.load()) + { + training.store(true); + } + } + + bool isTraining ( void ) const + { + return training.load(); + } + + void update ( void ) + { // To be called in your main loop + if (doneTraining.load()) + { + if (newModel) + { + std::swap(model, newModel); + } else + printf("New model was not created successfully...\n"); + + if (doneTrainingCallback) + doneTrainingCallback(); + doneTraining.store(false); + } + } + +protected: + void mainThreadCallback ( void ) + { // Training thread + if (isTraining()) + { + if (newModel) + delete newModel; + + newModel = new T(); + if (threadedTrainCallback) + threadedTrainCallback(newModel); + + training.store(false); + doneTraining.store(true); + } + usleep(100000); // Sleep 100 ms + } + + std::atomic<bool> training; + std::atomic<bool> doneTraining; + T* newModel = nullptr; + +private: +}; + +#endif /* RapidMixThread_h */ diff --git a/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp b/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..401bc7049ff06c6198b98d83b30f4f67c5659939 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp @@ -0,0 +1,222 @@ +/* + * RingBuffer.hpp + */ + +#ifndef RINGBUFFER_HPP +#define RINGBUFFER_HPP + +#include <iostream> +#include <atomic> +#include <string> +#include <unistd.h> +#include <string.h> // memcpy +#include <cstring> + +template <class T> +class RingBuffer +{ +public: + RingBuffer(); + RingBuffer(unsigned long size); + ~RingBuffer(); + void setup(unsigned long size); + + unsigned long push(const T* data, unsigned long n); + unsigned long pop(T* data, unsigned long n); + unsigned long items_available_for_write() const; + unsigned long items_available_for_read() const; + bool isLockFree() const; + void pushMayBlock(bool block); + void popMayBlock(bool block); + void setBlockingNap(unsigned long blockingNap); + void setSize(unsigned long size); + void reset(); + +private: + unsigned long array_size; + T* buffer = nullptr; + long type_size; // also depends on #channels + + std::atomic<unsigned long> tail_index; // write pointer + std::atomic<unsigned long> head_index; // read pointer + + bool blockingPush; + bool blockingPop; + useconds_t blockingNap = 500; +}; // RingBuffer{} + +template <class T> +RingBuffer<T>::RingBuffer() +{ + tail_index = 0; + head_index = 0; + + blockingPush = false; + blockingPop = false; +} // RingBuffer() + +template <class T> +RingBuffer<T>::RingBuffer(unsigned long array_size) +{ + tail_index = 0; + head_index = 0; + + blockingPush = false; + blockingPop = false; + + setup(array_size); +} // RingBuffer() + +template <class T> +RingBuffer<T>::~RingBuffer() +{ + if (buffer) + delete [] buffer; +} // ~RingBuffer() + +template <class T> +void RingBuffer<T>::setup(unsigned long array_size) +{ + if (buffer) + delete [] buffer; + + this->array_size = array_size; + buffer = new T [array_size](); // allocate storage + type_size = sizeof(T); +} + +template <class T> +unsigned long RingBuffer<T>::items_available_for_write() const +{ + long pointerspace = head_index.load()-tail_index.load(); // signed + + if(pointerspace > 0) return pointerspace; // NB: > 0 so NOT including 0 + else return pointerspace + array_size; +} // items_available_for_write() + +template <class T> +unsigned long RingBuffer<T>::items_available_for_read() const +{ + long pointerspace = tail_index.load() - head_index.load(); // signed + + if(pointerspace >= 0) return pointerspace; // NB: >= 0 so including 0 + else return pointerspace + array_size; +} // items_available_for_read() + +template <class T> +void RingBuffer<T>::pushMayBlock(bool block) +{ + this->blockingPush = block; +} // pushMayBlock() + +template <class T> +void RingBuffer<T>::popMayBlock(bool block) +{ + this->blockingPop = block; +} // popMayBlock() + +template <class T> +void RingBuffer<T>::setBlockingNap(unsigned long blockingNap) +{ + this->blockingNap = blockingNap; +} // setBlockingNap() + + +/* + * Try to write as many items as possible and return the number actually written + */ +template <class T> +unsigned long RingBuffer<T>::push(const T* data, unsigned long n) +{ + unsigned long space = array_size, n_to_write, memory_to_write, first_chunk, second_chunk, current_tail; + + //space = items_available_for_write(); + if(blockingPush) + { + while((space = items_available_for_write()) < n) + { // blocking + usleep(blockingNap); + } // while, possibly use a system level sleep operation with CVAR? + } // if + + n_to_write = (n <= space) ? n : space; // limit + + current_tail = tail_index.load(); + if(current_tail + n_to_write <= array_size) + { // chunk fits without wrapping + memory_to_write = n_to_write * type_size; + memcpy(buffer+current_tail, data, memory_to_write); + tail_index.store(current_tail + n_to_write); + } + else { // chunk has to wrap + first_chunk = array_size - current_tail; + memory_to_write = first_chunk * type_size; + memcpy(buffer + current_tail, data, memory_to_write); + + second_chunk = n_to_write - first_chunk; + memory_to_write = second_chunk * type_size; + memcpy(buffer, data + first_chunk, memory_to_write); + tail_index.store(second_chunk); + } + + return n_to_write; +} // push() + + +/* + * Try to read as many items as possible and return the number actually read + */ +template <class T> +unsigned long RingBuffer<T>::pop(T* data, unsigned long n) +{ + unsigned long space = array_size, n_to_read, memory_to_read, first_chunk, second_chunk, current_head; + + //space = items_available_for_read(); //if checking outside of thread, not necessary? + if(blockingPop) + { + while((space = items_available_for_read()) < n) + { // blocking + usleep(blockingNap); + } // while + } // if + + if(space == 0) + return 0; + + n_to_read = (n <= space) ? n : space; // limit + + current_head = head_index.load(); + if(current_head + n_to_read <= array_size) + { // no wrapping necessary + memory_to_read = n_to_read * type_size; + memcpy(data, buffer + current_head, memory_to_read); + head_index.store(current_head + n_to_read); + } + else { // read has to wrap + first_chunk = array_size - current_head; + memory_to_read = first_chunk * type_size; + memcpy(data, buffer + current_head, memory_to_read); + + second_chunk = n_to_read - first_chunk; + memory_to_read = second_chunk * type_size; + memcpy(data + first_chunk, buffer, memory_to_read); + head_index.store(second_chunk); + + } + return n_to_read; +} // pop() + +template <class T> +bool RingBuffer<T>::isLockFree() const +{ + return (tail_index.is_lock_free() && head_index.is_lock_free()); +} // isLockFree() + +template <class T> +void RingBuffer<T>::reset() +{ + tail_index.store(0); + head_index.store(0); +} // isLockFree() + +#endif diff --git a/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h b/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h new file mode 100644 index 0000000000000000000000000000000000000000..4f9d5949639fef2a396211d5fe57ca7ce835c5b1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h @@ -0,0 +1,74 @@ +// +// ThreadedProcess.h +// Bitalino +// +// Created by James on 19/11/2017. +// +// + +#ifndef ThreadedProcess_h +#define ThreadedProcess_h + +#include <stdio.h> +#include <stdint.h> +#include <functional> +#include <thread> +#include <atomic> + +class ThreadedProcess { +public: + ThreadedProcess ( void ) + { + running.store( false ); + } + + virtual ~ThreadedProcess ( void ) + { + stopThread(); + } + + bool isThreadRunning ( void ) const + { + return running.load(); + } + + // (re)Start main thread + void startThread ( void ) + { + if (running.load()) + { // Thread is already running + stopThread(); + } + running.store( true ); + processMainThread = std::thread(&ThreadedProcess::mainLoop, this); // Spawn thread + } + + // Stop main thread + void stopThread ( void ) + { + if (running.load()) + { + running.store( false ); + processMainThread.join(); + } + } + +protected: + virtual void mainThreadCallback ( void ) = 0; + + std::thread processMainThread; + +private: + void mainLoop ( void ) + { + while (running.load()) + { + mainThreadCallback(); + } + } + + std::atomic<bool> running; +}; + + +#endif /* ThreadedProcess_h */ diff --git a/examples/ofx/Bitalino_rapidmix/src/bitalino.cpp b/examples/ofx/Bitalino_rapidmix/src/bitalino.cpp new file mode 100755 index 0000000000000000000000000000000000000000..fe75bb9a3006de4fb3cc5ac1ec1ac1f0faf83550 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/bitalino.cpp @@ -0,0 +1,799 @@ +/** + * \copyright Copyright 2014-2016 PLUX - Wireless Biosignals, S.A. + * \author Filipe Silva + * \version 2.1 + * \date February 2016 + * + * \section LICENSE + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + */ + +/*****************************************************************************/ + +#ifdef _WIN32 // 32-bit or 64-bit Windows + +#define HASBLUETOOTH + +#define _WINSOCK_DEPRECATED_NO_WARNINGS + +#include <winsock2.h> +#include <ws2bth.h> + +#else // Linux or Mac OS + +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> + +#ifdef HASBLUETOOTH // Linux only + +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <stdlib.h> + +#endif // HASBLUETOOTH + +void Sleep(int millisecs) +{ + usleep(millisecs*1000); +} + +#endif // Linux or Mac OS + + +#include "bitalino.h" + +/*****************************************************************************/ + +// CRC4 check function + +static const unsigned char CRC4tab[16] = {0, 3, 6, 5, 12, 15, 10, 9, 11, 8, 13, 14, 7, 4, 1, 2}; + +static bool checkCRC4(const unsigned char *data, int len) +{ + unsigned char crc = 0; + + for (int i = 0; i < len-1; i++) + { + const unsigned char b = data[i]; + crc = CRC4tab[crc] ^ (b >> 4); + crc = CRC4tab[crc] ^ (b & 0x0F); + } + + // CRC for last byte + crc = CRC4tab[crc] ^ (data[len-1] >> 4); + crc = CRC4tab[crc]; + + return (crc == (data[len-1] & 0x0F)); +} + +/*****************************************************************************/ + +// BITalino public methods + +BITalino::VDevInfo BITalino::find(void) +{ + VDevInfo devs; + DevInfo devInfo; + +#ifdef _WIN32 + char addrStr[40]; + WSADATA m_data; + + if (WSAStartup(0x202, &m_data) != 0) throw Exception(Exception::PORT_INITIALIZATION); + + WSAQUERYSETA querySet; + ZeroMemory(&querySet, sizeof querySet); + querySet.dwSize = sizeof(querySet); + querySet.dwNameSpace = NS_BTH; + + HANDLE hLookup; + DWORD flags = LUP_CONTAINERS | LUP_RETURN_ADDR | LUP_RETURN_NAME | LUP_FLUSHCACHE; + bool tryempty = true; + bool again; + + do + { + again = false; + if (WSALookupServiceBeginA(&querySet, flags, &hLookup) != 0) + { + WSACleanup(); + throw Exception(Exception::BT_ADAPTER_NOT_FOUND); + } + + while (1) + { + BYTE buffer[1500]; + DWORD bufferLength = sizeof(buffer); + WSAQUERYSETA *pResults = (WSAQUERYSETA*)&buffer; + if (WSALookupServiceNextA(hLookup, flags, &bufferLength, pResults) != 0) break; + if (pResults->lpszServiceInstanceName[0] == 0 && tryempty) + { // empty name : may happen on the first inquiry after the device was connected + tryempty = false; // redo the inquiry a second time only (there may be a device with a real empty name) + again = true; + break; + } + + DWORD strSiz = sizeof addrStr; + if (WSAAddressToStringA(pResults->lpcsaBuffer->RemoteAddr.lpSockaddr, pResults->lpcsaBuffer->RemoteAddr.iSockaddrLength, + NULL, addrStr, &strSiz) == 0) + { + addrStr[strlen(addrStr)-1] = 0; // remove trailing ')' + devInfo.macAddr = addrStr+1; // remove leading '(' + devInfo.name = pResults->lpszServiceInstanceName; + devs.push_back(devInfo); + } + } + + WSALookupServiceEnd(hLookup); + } while (again); + + WSACleanup(); + +#else // Linux or Mac OS + +#ifdef HASBLUETOOTH + + #define MAX_DEVS 255 + + int dev_id = hci_get_route(NULL); + int sock = hci_open_dev(dev_id); + if (dev_id < 0 || sock < 0) + throw Exception(Exception::PORT_INITIALIZATION); + + inquiry_info ii[MAX_DEVS]; + inquiry_info *pii = ii; + + int num_rsp = hci_inquiry(dev_id, 8, MAX_DEVS, NULL, &pii, IREQ_CACHE_FLUSH); + if(num_rsp < 0) + { + ::close(sock); + throw Exception(Exception::PORT_INITIALIZATION); + } + + for (int i = 0; i < num_rsp; i++) + { + char addr[19], name[248]; + + ba2str(&ii[i].bdaddr, addr); + if (hci_read_remote_name(sock, &ii[i].bdaddr, sizeof name, name, 0) >= 0) + { + devInfo.macAddr = addr; + devInfo.name = name; + devs.push_back(devInfo); + } + } + + ::close(sock); + if (pii != ii) free(pii); + +#else + + throw Exception(Exception::BT_ADAPTER_NOT_FOUND); + +#endif // HASBLUETOOTH + +#endif // Linux or Mac OS + + return devs; +} + +/*****************************************************************************/ + +BITalino::BITalino(const char *address) : nChannels(0), isBitalino2(false) +{ +#ifdef _WIN32 + if (_memicmp(address, "COM", 3) == 0) + { + fd = INVALID_SOCKET; + + char xport[40] = "\\\\.\\"; // preppend "\\.\" + + strcat_s(xport, 40, address); + + hCom = CreateFileA(xport, // comm port name + GENERIC_READ | GENERIC_WRITE, + 0, // comm devices must be opened w/exclusive-access + NULL, // no security attributes + OPEN_EXISTING, // comm devices must use OPEN_EXISTING + 0, // not overlapped I/O + NULL); // hTemplate must be NULL for comm devices + + if (hCom == INVALID_HANDLE_VALUE) + throw Exception(Exception::PORT_COULD_NOT_BE_OPENED); + + DCB dcb; + if (!GetCommState(hCom, &dcb)) + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + dcb.BaudRate = CBR_115200; + dcb.fBinary = TRUE; + dcb.fParity = FALSE; + dcb.fOutxCtsFlow = FALSE; + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fDsrSensitivity = FALSE; + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + dcb.fNull = FALSE; + dcb.fRtsControl = RTS_CONTROL_ENABLE; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; + if (!SetCommState(hCom, &dcb)) + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + + COMMTIMEOUTS ct; + ct.ReadIntervalTimeout = 0; + ct.ReadTotalTimeoutConstant = 5000; // 5 s + ct.ReadTotalTimeoutMultiplier = 0; + ct.WriteTotalTimeoutConstant = 5000; // 5 s + ct.WriteTotalTimeoutMultiplier = 0; + + if (!SetCommTimeouts(hCom, &ct)) + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + } + else // address is a Bluetooth MAC address + { + hCom = INVALID_HANDLE_VALUE; + + WSADATA m_data; + if (WSAStartup(0x202, &m_data) != 0) + throw Exception(Exception::PORT_INITIALIZATION); + + SOCKADDR_BTH so_bt; + int siz = sizeof so_bt; + if (WSAStringToAddressA((LPSTR)address, AF_BTH, NULL, (sockaddr*)&so_bt, &siz) != 0) + { + WSACleanup(); + throw Exception(Exception::INVALID_ADDRESS); + } + so_bt.port = 1; + + fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); + if (fd == INVALID_SOCKET) + { + WSACleanup(); + throw Exception(Exception::PORT_INITIALIZATION); + } + + DWORD rcvbufsiz = 128*1024; // 128k + setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*) &rcvbufsiz, sizeof rcvbufsiz); + + if (connect(fd, (const sockaddr*)&so_bt, sizeof so_bt) != 0) + { + int err = WSAGetLastError(); + close(); + + switch(err) + { + case WSAENETDOWN: + throw Exception(Exception::BT_ADAPTER_NOT_FOUND); + + case WSAETIMEDOUT: + throw Exception(Exception::DEVICE_NOT_FOUND); + + default: + throw Exception(Exception::PORT_COULD_NOT_BE_OPENED); + } + } + + readtimeout.tv_sec = 5; + readtimeout.tv_usec = 0; + } + +#else // Linux or Mac OS + + if (memcmp(address, "/dev/", 5) == 0) + { + fd = open(address, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd < 0) + throw Exception(Exception::PORT_COULD_NOT_BE_OPENED); + + if (fcntl(fd, F_SETFL, 0) == -1) // remove the O_NDELAY flag + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + + termios term; + if (tcgetattr(fd, &term) != 0) + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + + cfmakeraw(&term); + term.c_oflag &= ~(OPOST); + + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 1; + + term.c_iflag &= ~(INPCK | PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXON | IXOFF | IMAXBEL); // no flow control + term.c_iflag |= (IGNPAR | IGNBRK); + + term.c_cflag &= ~(CRTSCTS | PARENB | CSTOPB | CSIZE); // no parity, 1 stop bit + term.c_cflag |= (CLOCAL | CREAD | CS8); // raw mode, 8 bits + + term.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL | ECHOCTL | ISIG | IEXTEN | TOSTOP); // raw mode + + if (cfsetspeed(&term, B115200) != 0) + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + + if (tcsetattr(fd, TCSANOW, &term) != 0) + { + close(); + throw Exception(Exception::PORT_INITIALIZATION); + } + + isTTY = true; + } + else // address is a Bluetooth MAC address +#ifdef HASBLUETOOTH + { + sockaddr_rc so_bt; + so_bt.rc_family = AF_BLUETOOTH; + if (str2ba(address, &so_bt.rc_bdaddr) < 0) + throw Exception(Exception::INVALID_ADDRESS); + + so_bt.rc_channel = 1; + + fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (fd < 0) + throw Exception(Exception::PORT_INITIALIZATION); + + if (connect(fd, (const sockaddr*)&so_bt, sizeof so_bt) != 0) + { + close(); + throw Exception(Exception::PORT_COULD_NOT_BE_OPENED); + } + + isTTY = false; + } +#else + throw Exception(Exception::PORT_COULD_NOT_BE_OPENED); +#endif // HASBLUETOOTH + +#endif // Linux or Mac OS + + // check if device is BITalino2 + const std::string ver = version(); + const std::string::size_type pos = ver.find("_v"); + if (pos != std::string::npos) + { + const char *xver = ver.c_str() + pos+2; + if (atoi(xver) >= 5) isBitalino2 = true; + } +} + +/*****************************************************************************/ + +BITalino::~BITalino(void) +{ + try + { + if (nChannels != 0) stop(); + } + catch (Exception) {} // if stop() fails, close anyway + + close(); +} + +/*****************************************************************************/ + +std::string BITalino::version(void) +{ + if (nChannels != 0) throw Exception(Exception::DEVICE_NOT_IDLE); + + const char *header = "BITalino"; + + const size_t headerLen = strlen(header); + + send(0x07); // 0 0 0 0 0 1 1 1 - Send version string + + std::string str; + while(1) + { + char chr; + if (recv(&chr, sizeof chr) != sizeof chr) // a timeout has occurred + throw Exception(Exception::CONTACTING_DEVICE); + + const size_t len = str.size(); + if (len >= headerLen) + { + if (chr == '\n') return str; + str.push_back(chr); + } + else + if (chr == header[len]) + str.push_back(chr); + else + { + str.clear(); // discard all data before version header + if (chr == header[0]) str.push_back(chr); + } + } +} + +/*****************************************************************************/ + +void BITalino::start(int samplingRate, const Vint &channels, bool simulated) +{ + if (nChannels != 0) throw Exception(Exception::DEVICE_NOT_IDLE); + + unsigned char cmd; + switch (samplingRate) + { + case 1: + cmd = 0x03; + break; + case 10: + cmd = 0x43; + break; + case 100: + cmd = 0x83; + break; + case 1000: + cmd = 0xC3; + break; + default: + throw Exception(Exception::INVALID_PARAMETER); + } + + char chMask; + if (channels.empty()) + { + chMask = 0x3F; // all 6 analog channels + nChannels = 6; + } + else + { + chMask = 0; + nChannels = 0; + for(Vint::const_iterator it = channels.begin(); it != channels.end(); it++) + { + int ch = *it; + if (ch < 0 || ch > 5) throw Exception(Exception::INVALID_PARAMETER); + const char mask = 1 << ch; + if (chMask & mask) throw Exception(Exception::INVALID_PARAMETER); + chMask |= mask; + nChannels++; + } + } + + send(cmd); // <Fs> 0 0 0 0 1 1 - Set sampling rate + + // A6 A5 A4 A3 A2 A1 0 1 - Start live mode with analog channel selection + // A6 A5 A4 A3 A2 A1 1 0 - Start simulated mode with analog channel selection + send((chMask << 2) | (simulated ? 0x02 : 0x01)); +} + +/*****************************************************************************/ + +void BITalino::stop(void) +{ + if (nChannels == 0) throw Exception(Exception::DEVICE_NOT_IN_ACQUISITION); + + send(0x00); // 0 0 0 0 0 0 0 0 - Go to idle mode + + nChannels = 0; + + version(); // to flush pending frames in input buffer +} + +/*****************************************************************************/ + +int BITalino::read(VFrame &frames) +{ + if (nChannels == 0) throw Exception(Exception::DEVICE_NOT_IN_ACQUISITION); + + unsigned char buffer[8]; // frame maximum size is 8 bytes + + if (frames.empty()) frames.resize(100); + + char nBytes = nChannels + 2; + if (nChannels >= 3 && nChannels <= 5) nBytes++; + + for(VFrame::iterator it = frames.begin(); it != frames.end(); it++) + { + if (recv(buffer, nBytes) != nBytes) return int(it - frames.begin()); // a timeout has occurred + + while (!checkCRC4(buffer, nBytes)) + { // if CRC check failed, try to resynchronize with the next valid frame + // checking with one new byte at a time + memmove(buffer, buffer+1, nBytes-1); + if (recv(buffer+nBytes-1, 1) != 1) return int(it - frames.begin()); // a timeout has occurred + } + + Frame &f = *it; + f.seq = buffer[nBytes-1] >> 4; + for(int i = 0; i < 4; i++) + f.digital[i] = ((buffer[nBytes-2] & (0x80 >> i)) != 0); + + f.analog[0] = (short(buffer[nBytes-2] & 0x0F) << 6) | (buffer[nBytes-3] >> 2); + if (nChannels > 1) + f.analog[1] = (short(buffer[nBytes-3] & 0x03) << 8) | buffer[nBytes-4]; + if (nChannels > 2) + f.analog[2] = (short(buffer[nBytes-5]) << 2) | (buffer[nBytes-6] >> 6); + if (nChannels > 3) + f.analog[3] = (short(buffer[nBytes-6] & 0x3F) << 4) | (buffer[nBytes-7] >> 4); + if (nChannels > 4) + f.analog[4] = ((buffer[nBytes-7] & 0x0F) << 2) | (buffer[nBytes-8] >> 6); + if (nChannels > 5) + f.analog[5] = buffer[nBytes-8] & 0x3F; + } + + return (int) frames.size(); +} + +/*****************************************************************************/ + +void BITalino::battery(int value) +{ + if (nChannels != 0) throw Exception(Exception::DEVICE_NOT_IDLE); + + if (value < 0 || value > 63) throw Exception(Exception::INVALID_PARAMETER); + + send(value << 2); // <bat threshold> 0 0 - Set battery threshold +} + +/*****************************************************************************/ + +void BITalino::trigger(const Vbool &digitalOutput) +{ + unsigned char cmd; + const size_t len = digitalOutput.size(); + + if (isBitalino2) + { + if (len != 0 && len != 2) throw Exception(Exception::INVALID_PARAMETER); + + cmd = 0xB3; // 1 0 1 1 O2 O1 1 1 - Set digital outputs + } + else + { + if (len != 0 && len != 4) throw Exception(Exception::INVALID_PARAMETER); + + if (nChannels == 0) throw Exception(Exception::DEVICE_NOT_IN_ACQUISITION); + + cmd = 0x03; // 0 0 O4 O3 O2 O1 1 1 - Set digital outputs + } + + for(size_t i = 0; i < len; i++) + if (digitalOutput[i]) + cmd |= (0x04 << i); + + send(cmd); +} + +/*****************************************************************************/ + +void BITalino::pwm(int pwmOutput) +{ + if (!isBitalino2) throw Exception(Exception::NOT_SUPPORTED); + + if (pwmOutput < 0 || pwmOutput > 255) throw Exception(Exception::INVALID_PARAMETER); + + send((char) 0xA3); // 1 0 1 0 0 0 1 1 - Set analog output (1 byte follows: 0..255) + send(pwmOutput); +} + +/*****************************************************************************/ + +BITalino::State BITalino::state(void) +{ +#pragma pack(1) // byte-aligned structure + + struct StateX + { + unsigned short analog[6], battery; + unsigned char batThreshold, portsCRC; + } statex; + +#pragma pack() // restore default alignment + + + if (!isBitalino2) throw Exception(Exception::NOT_SUPPORTED); + + if (nChannels != 0) throw Exception(Exception::DEVICE_NOT_IDLE); + + send(0x0B); // 0 0 0 0 1 0 1 1 - Send device status + + if (recv(&statex, sizeof statex) != sizeof statex) // a timeout has occurred + throw Exception(Exception::CONTACTING_DEVICE); + + if (!checkCRC4((unsigned char *) &statex, sizeof statex)) + throw Exception(Exception::CONTACTING_DEVICE); + + State state; + + for(int i = 0; i < 6; i++) + state.analog[i] = statex.analog[i]; + + state.battery = statex.battery; + state.batThreshold = statex.batThreshold; + + for(int i = 0; i < 4; i++) + state.digital[i] = ((statex.portsCRC & (0x80 >> i)) != 0); + + return state; +} + +/*****************************************************************************/ + +const char* BITalino::Exception::getDescription(void) +{ + switch (code) + { + case INVALID_ADDRESS: + return "The specified address is invalid."; + + case BT_ADAPTER_NOT_FOUND: + return "No Bluetooth adapter was found."; + + case DEVICE_NOT_FOUND: + return "The device could not be found."; + + case CONTACTING_DEVICE: + return "The computer lost communication with the device."; + + case PORT_COULD_NOT_BE_OPENED: + return "The communication port does not exist or it is already being used."; + + case PORT_INITIALIZATION: + return "The communication port could not be initialized."; + + case DEVICE_NOT_IDLE: + return "The device is not idle."; + + case DEVICE_NOT_IN_ACQUISITION: + return "The device is not in acquisition mode."; + + case INVALID_PARAMETER: + return "Invalid parameter."; + + case NOT_SUPPORTED: + return "Operation not supported by the device."; + + default: + return "Unknown error."; + } +} + +/*****************************************************************************/ + +// BITalino private methods + +void BITalino::send(char cmd) +{ + Sleep(150); + +#ifdef _WIN32 + if (fd == INVALID_SOCKET) + { + DWORD nbytwritten = 0; + if (!WriteFile(hCom, &cmd, sizeof cmd, &nbytwritten, NULL)) + throw Exception(Exception::CONTACTING_DEVICE); + + if (nbytwritten != sizeof cmd) + throw Exception(Exception::CONTACTING_DEVICE); + } + else + if (::send(fd, &cmd, sizeof cmd, 0) != sizeof cmd) + throw Exception(Exception::CONTACTING_DEVICE); + +#else // Linux or Mac OS + + if (write(fd, &cmd, sizeof cmd) != sizeof cmd) + throw Exception(Exception::CONTACTING_DEVICE); +#endif +} + +/*****************************************************************************/ + +int BITalino::recv(void *data, int nbyttoread) +{ +#ifdef _WIN32 + if (fd == INVALID_SOCKET) + { + for(int n = 0; n < nbyttoread;) + { + DWORD nbytread = 0; + if (!ReadFile(hCom, (char *) data+n, nbyttoread-n, &nbytread, NULL)) + throw Exception(Exception::CONTACTING_DEVICE); + + if (nbytread == 0) + { + DWORD stat; + if (!GetCommModemStatus(hCom, &stat) || !(stat & MS_DSR_ON)) + throw Exception(Exception::CONTACTING_DEVICE); // connection is lost + + return n; // a timeout occurred + } + + n += nbytread; + } + + return nbyttoread; + } +#endif + +#ifndef _WIN32 // Linux or Mac OS + timeval readtimeout; + readtimeout.tv_sec = 5; + readtimeout.tv_usec = 0; +#endif + + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + for(int n = 0; n < nbyttoread;) + { + int state = select(FD_SETSIZE, &readfds, NULL, NULL, &readtimeout); + if(state < 0) throw Exception(Exception::CONTACTING_DEVICE); + + if (state == 0) return n; // a timeout occurred + +#ifdef _WIN32 + int ret = ::recv(fd, (char *) data+n, nbyttoread-n, 0); +#else // Linux or Mac OS + ssize_t ret = ::read(fd, (char *) data+n, nbyttoread-n); +#endif + + if(ret <= 0) throw Exception(Exception::CONTACTING_DEVICE); + n += ret; + } + + return nbyttoread; +} + +/*****************************************************************************/ + +void BITalino::close(void) +{ +#ifdef _WIN32 + if (fd == INVALID_SOCKET) + CloseHandle(hCom); + else + { + closesocket(fd); + WSACleanup(); + } + +#else // Linux or Mac OS + + ::close(fd); + +#endif +} + +/*****************************************************************************/ diff --git a/examples/ofx/Bitalino_rapidmix/src/bitalino.h b/examples/ofx/Bitalino_rapidmix/src/bitalino.h new file mode 100755 index 0000000000000000000000000000000000000000..bee7ccf255de2d725409002d9bc061dd1ef96bf1 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/bitalino.h @@ -0,0 +1,319 @@ +/** + * \file + * \copyright Copyright 2014-2015 PLUX - Wireless Biosignals, S.A. + * \author Filipe Silva + * \version 2.0 + * \date November 2015 + * + * \section LICENSE + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + */ + + + /** + \mainpage + + The %BITalino C++ API (available at http://github.com/BITalinoWorld/cpp-api) is a cross-platform library which enables C++ applications to communicate + with a %BITalino device through a simple interface. + The API is composed of a header file (bitalino.h) + and an implementation file ([bitalino.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.cpp)). + A sample test application in C++ ([test.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/test.cpp)) is also provided. + + There are three ways to connect to a %BITalino device: + - direct Bluetooth connection using the device Bluetooth MAC address (Windows and Linux); + - indirect Bluetooth connection using a virtual serial port (all platforms); + - wired UART connection using a serial port (all platforms). + + The API exposes a single class (BITalino). Each instance of this class represents a connection + to a %BITalino device. The connection is established in the constructor and released in the destructor, + thus following the RAII paradigm. An application can create several instances (to distinct devices). + The library is thread-safe between distinct instances. Each instance can be a local variable + (as in the sample application) or it can be allocated on the heap (using new and delete operators). + + \section sampleapp About the sample application + + The sample application ([test.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/test.cpp)) creates an instance to a %BITalino device. + Then it starts acquiring all channels on the device at 1000 Hz and enters a loop while dumping + one frame out of 100 and toggling the device green LED. Pressing the Enter key exits the loop, + destroys the instance and closes the application. + + One of the provided constructor calls must be used to connect to the device. + The string passed to the constructor can be a Bluetooth MAC address (you must change the one provided) + or a serial port. The serial port string format depends on the platform. + + In order to have a more compact and readable code, the sample test code uses C++11 vector initializer lists. + This new C++ feature is supported only in Visual Studio 2013 or later (on Windows), GCC 4.4 or later and Clang 3.1 + or later. If you are using an older compiler, use the commented alternative code for the `start()` and + `trigger()` methods calls. + + \section windows Compiling on Windows + + The API was tested in Windows 7 (32-bit and 64-bit). + + To compile the library and the sample application: + - create a C++ Empty Project in Visual Studio; + - copy [bitalino.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.cpp), + [bitalino.h](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.h) and + [test.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/test.cpp) to the project directory; + - add bitalino.cpp and test.cpp files to the project at the “Source Files†folder; + - edit test.cpp as described \ref sampleapp "above"; + - add a reference to `ws2_32.lib` in Project Properties → Configuration Properties → Linker → Input → Additional Dependencies; + - build the solution and run the application. + + \section linux Compiling on Linux + + The API was tested in Ubuntu (32-bit and 64-bit) and Raspberry Pi (Raspbian). + + To compile the library and the sample application: + - `make` and `g++` must be installed; + - packages `bluez`, `libbluetooth3` and `libbluetooth-dev` must be installed if you want to + compile the library with Bluetooth functionality (to search for Bluetooth devices and + to make direct Bluetooth connections); + - copy [bitalino.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.cpp), + [bitalino.h](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.h), + [test.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/test.cpp) and + [Makefile](http://github.com/BITalinoWorld/cpp-api/tree/master/Makefile) into a new directory; + - if you want to compile the library without Bluetooth functionality, disable the line in + Makefile where `LINUX_BT` is defined; + - if your compiler doesn't support vector initializer lists, remove the flag `-std=c++0x` + from the test.cpp compiling rule in Makefile; + - edit test.cpp as described \ref sampleapp "above"; + - enter command `make` in the command line to build the library and the application; + - enter command `./test` in the command line to run the application. + + \section macosx Compiling on Mac OS X + + The API was tested in Mac OS X 10.6 and 10.9. + + On Mac OS X, the %BITalino API Bluetooth functionality is not available, so it is only possible + to connect to a %BITalino device through a serial port for indirect Bluetooth connections or for wired UART connections. + + To compile the library and the sample application: + - copy [bitalino.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.cpp), + [bitalino.h](http://github.com/BITalinoWorld/cpp-api/tree/master/bitalino.h), + [test.cpp](http://github.com/BITalinoWorld/cpp-api/tree/master/test.cpp) and + [Makefile](http://github.com/BITalinoWorld/cpp-api/tree/master/Makefile) into a new directory; + - if your compiler doesn't support vector initializer lists, remove the flag `-std=c++0x` from + the test.cpp compiling rule in Makefile; + - edit test.cpp as described \ref sampleapp "above"; + - enter command `make` in the command line to build the library and the application; + - enter command `./test` in the command line to run the application. + */ + +#ifndef _BITALINOHEADER_ +#define _BITALINOHEADER_ + +#include <string> +#include <vector> + +#ifdef _WIN32 // 32-bit or 64-bit Windows + +#include <winsock2.h> + +#endif + +/// The %BITalino device class. +class BITalino +{ +public: +// Type definitions + + typedef std::vector<bool> Vbool; ///< Vector of bools. + typedef std::vector<int> Vint; ///< Vector of ints. + + /// Information about a Bluetooth device found by BITalino::find(). + struct DevInfo + { + std::string macAddr; ///< MAC address of a Bluetooth device + std::string name; ///< Name of a Bluetooth device + }; + typedef std::vector<DevInfo> VDevInfo; ///< Vector of DevInfo's. + + /// A frame returned by BITalino::read() + struct Frame + { + /// %Frame sequence number (0...15). + /// This number is incremented by 1 on each consecutive frame, and it overflows to 0 after 15 (it is a 4-bit number). + /// This number can be used to detect if frames were dropped while transmitting data. + char seq; + + /// Array of digital ports states (false for low level or true for high level). + /// On original %BITalino, the array contents are: I1 I2 I3 I4. + /// On %BITalino 2, the array contents are: I1 I2 O1 O2. + bool digital[4]; + + /// Array of analog inputs values (0...1023 on the first 4 channels and 0...63 on the remaining channels) + short analog[6]; + }; + typedef std::vector<Frame> VFrame; ///< Vector of Frame's. + + /// Current device state returned by BITalino::state() + struct State + { + int analog[6], ///< Array of analog inputs values (0...1023) + battery, ///< Battery voltage value (0...1023) + batThreshold; ///< Low-battery LED threshold (last value set with BITalino::battery()) + /// Array of digital ports states (false for low level or true for high level). + /// The array contents are: I1 I2 O1 O2. + bool digital[4]; + }; + + /// %Exception class thrown from BITalino methods. + class Exception + { + public: + /// %Exception code enumeration. + enum Code + { + INVALID_ADDRESS = 1, ///< The specified address is invalid + BT_ADAPTER_NOT_FOUND, ///< No Bluetooth adapter was found + DEVICE_NOT_FOUND, ///< The device could not be found + CONTACTING_DEVICE, ///< The computer lost communication with the device + PORT_COULD_NOT_BE_OPENED, ///< The communication port does not exist or it is already being used + PORT_INITIALIZATION, ///< The communication port could not be initialized + DEVICE_NOT_IDLE, ///< The device is not idle + DEVICE_NOT_IN_ACQUISITION, ///< The device is not in acquisition mode + INVALID_PARAMETER, ///< Invalid parameter + NOT_SUPPORTED, ///< Operation not supported by the device + } code; ///< %Exception code. + + Exception(Code c) : code(c) {} ///< Exception constructor. + const char* getDescription(void); ///< Returns an exception description string + }; + +// Static methods + + /** Searches for Bluetooth devices in range. + * \return a list of found devices + * \exception Exception (Exception::PORT_INITIALIZATION) + * \exception Exception (Exception::BT_ADAPTER_NOT_FOUND) + */ + static VDevInfo find(void); + +// Instance methods + + /** Connects to a %BITalino device. + * \param[in] address The device Bluetooth MAC address ("xx:xx:xx:xx:xx:xx") + * or a serial port ("COMx" on Windows or "/dev/..." on Linux or Mac OS X) + * \exception Exception (Exception::PORT_COULD_NOT_BE_OPENED) + * \exception Exception (Exception::PORT_INITIALIZATION) + * \exception Exception (Exception::INVALID_ADDRESS) + * \exception Exception (Exception::BT_ADAPTER_NOT_FOUND) - Windows only + * \exception Exception (Exception::DEVICE_NOT_FOUND) - Windows only + */ + BITalino(const char *address); + + /// Disconnects from a %BITalino device. If an aquisition is running, it is stopped. + ~BITalino(); + + /** Returns the device firmware version string. + * \remarks This method cannot be called during an acquisition. + * \exception Exception (Exception::DEVICE_NOT_IDLE) + * \exception Exception (Exception::CONTACTING_DEVICE) + */ + std::string version(void); + + /** Starts a signal acquisition from the device. + * \param[in] samplingRate Sampling rate in Hz. Accepted values are 1, 10, 100 or 1000 Hz. Default value is 1000 Hz. + * \param[in] channels Set of channels to acquire. Accepted channels are 0...5 for inputs A1...A6. + * If this set is empty or if it is not given, all 6 analog channels will be acquired. + * \param[in] simulated If true, start in simulated mode. Otherwise start in live mode. Default is to start in live mode. + * \remarks This method cannot be called during an acquisition. + * \exception Exception (Exception::DEVICE_NOT_IDLE) + * \exception Exception (Exception::INVALID_PARAMETER) + * \exception Exception (Exception::CONTACTING_DEVICE) + */ + void start(int samplingRate = 1000, const Vint &channels = Vint(), bool simulated = false); + + /** Stops a signal acquisition. + * \remarks This method must be called only during an acquisition. + * \exception Exception (Exception::DEVICE_NOT_IN_ACQUISITION) + * \exception Exception (Exception::CONTACTING_DEVICE) + */ + void stop(void); + + /** Reads acquisition frames from the device. + * This method returns when all requested frames are received from the device, or when 5-second receive timeout occurs. + * \param[out] frames Vector of frames to be filled. If the vector is empty, it is resized to 100 frames. + * \return Number of frames returned in frames vector. If a timeout occurred, this number is less than the frames vector size. + * \remarks This method must be called only during an acquisition. + * \exception Exception (Exception::DEVICE_NOT_IN_ACQUISITION) + * \exception Exception (Exception::CONTACTING_DEVICE) + */ + int read(VFrame &frames); + + /** Sets the battery voltage threshold for the low-battery LED. + * \param[in] value Battery voltage threshold. Default value is 0. + * Value | Voltage Threshold + * ----- | ----------------- + * 0 | 3.4 V + * ... | ... + * 63 | 3.8 V + * \remarks This method cannot be called during an acquisition. + * \exception Exception (Exception::DEVICE_NOT_IDLE) + * \exception Exception (Exception::INVALID_PARAMETER) + * \exception Exception (Exception::CONTACTING_DEVICE) + */ + void battery(int value = 0); + + /** Assigns the digital outputs states. + * \param[in] digitalOutput Vector of booleans to assign to digital outputs, starting at first output (O1). + * On each vector element, false sets the output to low level and true sets the output to high level. + * If this vector is not empty, it must contain exactly 4 elements for original %BITalino (4 digital outputs) + * or exactly 2 elements for %BITalino 2 (2 digital outputs). + * If this parameter is not given or if the vector is empty, all digital outputs are set to low level. + * \remarks This method must be called only during an acquisition on original %BITalino. On %BITalino 2 there is no restriction. + * \exception Exception (Exception::DEVICE_NOT_IN_ACQUISITION) + * \exception Exception (Exception::INVALID_PARAMETER) + * \exception Exception (Exception::CONTACTING_DEVICE) + */ + void trigger(const Vbool &digitalOutput = Vbool()); + + /** Assigns the analog (PWM) output value (%BITalino 2 only). + * \param[in] pwmOutput Analog output value to set (0...255). + * The analog output voltage is given by: V (in Volts) = 3.3 * (pwmOutput+1)/256 + * \exception Exception (Exception::INVALID_PARAMETER) + * \exception Exception (Exception::CONTACTING_DEVICE) + * \exception Exception (Exception::NOT_SUPPORTED) + */ + void pwm(int pwmOutput = 100); + + /** Returns current device state (%BITalino 2 only). + * \remarks This method cannot be called during an acquisition. + * \exception Exception (Exception::DEVICE_NOT_IDLE) + * \exception Exception (Exception::CONTACTING_DEVICE) + * \exception Exception (Exception::NOT_SUPPORTED) + */ + State state(void); + +private: + void send(char cmd); + int recv(void *data, int nbyttoread); + void close(void); + + char nChannels; + bool isBitalino2; +#ifdef _WIN32 + SOCKET fd; + timeval readtimeout; + HANDLE hCom; +#else // Linux or Mac OS + int fd; + bool isTTY; +#endif +}; + +#endif // _BITALINOHEADER_ diff --git a/examples/ofx/Bitalino_rapidmix/src/main.cpp b/examples/ofx/Bitalino_rapidmix/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e57370b26ee652c85ce0b32f19eace3b681585a4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/main.cpp @@ -0,0 +1,13 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp b/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b156ff1d90ec33be5a3a4c84191aa5e42b782651 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp @@ -0,0 +1,111 @@ +#include "ofApp.h" + +//-------------------------------------------------------------- +void ofApp::setup(){ + rapidBitalino.setup(); +} + +//-------------------------------------------------------------- +void ofApp::update(){ + rapidBitalino.update(); + /* + static bool connection = false; + bool connectionStatus = BT.isConnected(); + if (connection != connectionStatus) + { + connection = connectionStatus; + if (connection) + { + printf("Connected after %u attempt(s)\n", BT.getConnectionTries()); + } + } + + uint32_t items = BT.data.items_available_for_read(); + BITalino::Frame tFrame; + for (uint32_t i = 0; i < items; ++i) + { + BT.data.pop(&tFrame, 1); + printf("%d \t : %d %d %d %d ; %d %d %d %d %d %d\n", // dump the first frame + tFrame.seq, + tFrame.digital[0], tFrame.digital[1], tFrame.digital[2], tFrame.digital[3], + tFrame.analog[0], tFrame.analog[1], tFrame.analog[2], tFrame.analog[3], tFrame.analog[4], tFrame.analog[5]); + } + */ +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + rapidBitalino.draw(); +} + +//-------------------------------------------------------------- +void ofApp::exit(){ + printf("stopping...\n"); + rapidBitalino.stop(); +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ + static uint32_t numTrainingData = 20; + if (key == 'c') { + rapidBitalino.clearTrainingData(); + } else if (key == '1') { + rapidBitalino.recordTrainingData(numTrainingData, 1.0); + } else if (key == '2') { + rapidBitalino.recordTrainingData(numTrainingData, 2.0); + } else if (key == '3') { + rapidBitalino.recordTrainingData(numTrainingData, 3.0); + } else if (key == '4') { + rapidBitalino.recordTrainingData(numTrainingData, 4.0); + } +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseEntered(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseExited(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/examples/ofx/Bitalino_rapidmix/src/ofApp.h b/examples/ofx/Bitalino_rapidmix/src/ofApp.h new file mode 100644 index 0000000000000000000000000000000000000000..2cf79a8f915a0148aef8f3b74ffa81893f2830a4 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/src/ofApp.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ofMain.h" +#include "RapidBitalino.h" + +class ofApp : public ofBaseApp{ + +public: + void setup(); + void update(); + void draw(); + void exit(); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseEntered(int x, int y); + void mouseExited(int x, int y); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + +private: + + RapidBitalino rapidBitalino; +};