changeset 0:8a575ba3ab52

Initial commit.
author andrewm
date Fri, 31 Oct 2014 19:10:17 +0100
parents
children 24fc8026ae8e
files .cproject .metadata/.plugins/org.eclipse.cdt.core/.log .metadata/.plugins/org.eclipse.cdt.make.core/specs.c .metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp .metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version .metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index .metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version .metadata/.plugins/org.eclipse.core.resources/.root/2.tree .metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources .metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.ui.prefs .metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs .metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs .metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs .metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs .metadata/.plugins/org.eclipse.jdt.core/invalidArchivesCache .metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache .metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat .metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml .metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml .metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml .metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml .metadata/.plugins/org.eclipse.ui.workbench/workbench.xml .metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml .metadata/version.ini .project .settings/org.eclipse.cdt.core.prefs core/GPIOcontrol.cpp core/I2c_Codec.cpp core/PRU.cpp core/RTAudio.cpp core/Utilities.cpp include/GPIOcontrol.h include/I2c.h include/I2c_Codec.h include/PRU.h include/RTAudio.h include/Utilities.h include/pruss_intc_mapping.h include/prussdrv.h include/render.h libNE10.a libprussdrv.a projects/basic/main.cpp projects/basic/render.cpp projects/basic_analog_output/main.cpp projects/basic_analog_output/render.cpp projects/basic_sensor/main.cpp projects/basic_sensor/render.cpp projects/d-box/ADSR.cpp projects/d-box/ADSR.h projects/d-box/AnalogInput.cpp projects/d-box/AnalogInput.h projects/d-box/Biquad.cpp projects/d-box/Biquad.h projects/d-box/DBoxSynth.h projects/d-box/DboxSensors.cpp projects/d-box/DboxSensors.h projects/d-box/FIRfilter.h projects/d-box/FeedbackOscillator.cpp projects/d-box/FeedbackOscillator.h projects/d-box/I2c_TouchKey.cpp projects/d-box/I2c_TouchKey.h projects/d-box/OscillatorBank.cpp projects/d-box/OscillatorBank.h projects/d-box/PinkNoise.cpp projects/d-box/PinkNoise.h projects/d-box/StatusLED.cpp projects/d-box/StatusLED.h projects/d-box/audio_routines.S projects/d-box/config.h projects/d-box/logger.cpp projects/d-box/logger.h projects/d-box/main.cpp projects/d-box/prio.cpp projects/d-box/prio.h projects/d-box/render.cpp projects/d-box/sensors.cpp projects/d-box/sensors.h projects/d-box/spear_parser.cpp projects/d-box/spear_parser.h projects/oscillator_bank/audio_routines.S projects/oscillator_bank/main.cpp projects/oscillator_bank/render.cpp pru_rtaudio.bin pru_rtaudio.p resources/BB-BONE-BAREAUDI-00A0.dtbo resources/BB-BONE-BAREAUDI-02-00A0.dts
diffstat 87 files changed, 10757 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.cproject	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.528876549">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.528876549" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.528876549" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug">
+					<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.528876549." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.681872250" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.295375065" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
+							<builder buildPath="${workspace_loc:/BBB_audio+input/Debug}" id="cdt.managedbuild.target.gnu.builder.exe.debug.26322421" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug">
+								<outputEntries>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name="Debug"/>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name="Release"/>
+								</outputEntries>
+							</builder>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1542380883" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool command="arm-linux-gnueabihf-g++" id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.2030825480" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug">
+								<option id="gnu.cpp.compiler.exe.debug.option.optimization.level.2006448218" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.more" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.exe.debug.option.debugging.level.1267706246" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.2031219124" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/xenomai/include"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/ne10"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.other.other.1516989263" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 -Wpointer-arith -Wunused-result -D_GNU_SOURCE -D_REENTRANT -D__XENO__" valueType="string"/>
+								<option id="gnu.cpp.compiler.option.warnings.allwarn.1392851614" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="true" valueType="boolean"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1166892316" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool command="arm-linux-gnueabihf-gcc" id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.917207395" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug">
+								<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.326761664" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" value="gnu.c.optimization.level.more" valueType="enumerated"/>
+								<option id="gnu.c.compiler.exe.debug.option.debugging.level.471732683" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.include.paths.358825414" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/xenomai/include"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/ne10"/>
+								</option>
+								<option id="gnu.c.compiler.option.misc.other.835792865" name="Other flags" superClass="gnu.c.compiler.option.misc.other" value="-c -fmessage-length=0 -Wpointer-arith -Wunused-result  -D_GNU_SOURCE -D_REENTRANT -D__XENO__ -std=gnu99" valueType="string"/>
+								<option id="gnu.c.compiler.option.warnings.allwarn.1145989346" name="All warnings (-Wall)" superClass="gnu.c.compiler.option.warnings.allwarn" value="true" valueType="boolean"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.308014221" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.214461086" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/>
+							<tool command="arm-linux-gnueabihf-g++" id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.1669966018" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug">
+								<option id="gnu.cpp.link.option.paths.462980690" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/lib"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/lib/xenomai"/>
+									<listOptionValue builtIn="false" value="/usr/lib/x86_64-linux-gnu"/>
+								</option>
+								<option id="gnu.cpp.link.option.libs.139390951" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="rt"/>
+									<listOptionValue builtIn="false" value="native"/>
+									<listOptionValue builtIn="false" value="xenomai"/>
+								</option>
+								<option id="gnu.cpp.link.option.flags.2096887116" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-pthread -rdynamics" valueType="string"/>
+								<option id="gnu.cpp.link.option.userobjs.537608578" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/libprussdrv.a}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/libNE10.a}&quot;"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.450978479" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool command="arm-linux-gnueabihf-as" id="cdt.managedbuild.tool.gnu.assembler.exe.debug.37270610" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug">
+								<option id="gnu.both.asm.option.include.paths.1403814918" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/xenomai/include"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/ne10"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1788972942" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/>
+						<entry excluding="d-box|basic_sensor|basic|basic_analog_output" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.config.gnu.exe.release.1521194538">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.1521194538" moduleId="org.eclipse.cdt.core.settings" name="Release">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1521194538" name="Release" parent="cdt.managedbuild.config.gnu.exe.release">
+					<folderInfo id="cdt.managedbuild.config.gnu.exe.release.1521194538." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1612059942" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.908983575" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/>
+							<builder buildPath="${workspace_loc:/BBB_audio+input/Release}" id="cdt.managedbuild.target.gnu.builder.exe.release.511190290" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.810674388" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool command="arm-linux-gnueabihf-g++" id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.163790048" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
+								<option id="gnu.cpp.compiler.exe.release.option.optimization.level.2031085570" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.more" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.exe.release.option.debugging.level.701035863" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.823255770" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/ne10"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/xenomai/include"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.601059736" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool command="arm-linux-gnueabihf-gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.1302828968" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
+								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.1118673208" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" value="gnu.c.optimization.level.more" valueType="enumerated"/>
+								<option id="gnu.c.compiler.exe.release.option.debugging.level.1329456558" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.include.paths.1269113471" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/include/xenomai/include"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.574072828" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.281634187" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/>
+							<tool command="arm-linux-gnueabihf-g++" id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.929570421" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release">
+								<option id="gnu.cpp.link.option.paths.277042583" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/lib"/>
+									<listOptionValue builtIn="false" value="/usr/arm-linux-gnueabihf/lib/xenomai"/>
+								</option>
+								<option id="gnu.cpp.link.option.libs.1930118082" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="rt"/>
+									<listOptionValue builtIn="false" value="native"/>
+									<listOptionValue builtIn="false" value="xenomai"/>
+								</option>
+								<option id="gnu.cpp.link.option.flags.1308374111" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-pthread -Wpointer-arith" valueType="string"/>
+								<option id="gnu.cpp.link.option.userobjs.1473502069" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/libprussdrv.a}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/libNE10.a}&quot;"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1607203279" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool command="arm-linux-gnueabihf-as" id="cdt.managedbuild.tool.gnu.assembler.exe.release.2052985276" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1212659593" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/>
+						<entry excluding="d-box|basic_sensor|basic|basic_analog_output" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="BBB_audio+input.cdt.managedbuild.target.gnu.exe.1596461844" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
+	</storageModule>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Release">
+			<resource resourceType="PROJECT" workspacePath="/BBB_SimpleInstrument"/>
+		</configuration>
+		<configuration configurationName="basic">
+			<resource resourceType="PROJECT" workspacePath="/BeagleRT"/>
+		</configuration>
+		<configuration configurationName="Debug">
+			<resource resourceType="PROJECT" workspacePath="/BBB_SimpleInstrument"/>
+		</configuration>
+	</storageModule>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1521194538;cdt.managedbuild.config.gnu.exe.release.1521194538.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.163790048;cdt.managedbuild.tool.gnu.cpp.compiler.input.601059736">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.528876549;cdt.managedbuild.config.gnu.exe.debug.528876549.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.2030825480;cdt.managedbuild.tool.gnu.cpp.compiler.input.1166892316">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.528876549;cdt.managedbuild.config.gnu.exe.debug.528876549.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.917207395;cdt.managedbuild.tool.gnu.c.compiler.input.308014221">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1521194538;cdt.managedbuild.config.gnu.exe.release.1521194538.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.1302828968;cdt.managedbuild.tool.gnu.c.compiler.input.574072828">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		</scannerConfigBuildInfo>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+	<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+</cproject>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.cdt.core/.log	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,3 @@
+*** SESSION Oct 17, 2013 09:50:56.88 -------------------------------------------
+*** SESSION Oct 17, 2013 09:51:41.97 -------------------------------------------
+*** SESSION Jul 22, 2014 19:36:22.66 -------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,1 @@
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,1 @@
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,1 @@
+
\ No newline at end of file
Binary file .metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,1 @@
+
\ No newline at end of file
Binary file .metadata/.plugins/org.eclipse.core.resources/.root/2.tree has changed
Binary file .metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.ui.prefs	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+spelling_locale_initialized=true
+useAnnotationsPrefPage=true
+useQuickDiffPrefPage=true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+version=1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,14 @@
+content_assist_proposals_background=255,255,255
+content_assist_proposals_foreground=60,60,60
+eclipse.preferences.version=1
+fontPropagated=true
+org.eclipse.jdt.internal.ui.navigator.layout=2
+org.eclipse.jdt.ui.editor.tab.width=
+org.eclipse.jdt.ui.formatterprofiles.version=12
+org.eclipse.jdt.ui.javadoclocations.migrated=true
+org.eclipse.jface.textfont=1|Monospace|10.0|0|GTK|1|;
+proposalOrderMigrated=true
+spelling_locale_initialized=true
+tabWidthPropagated=true
+useAnnotationsPrefPage=true
+useQuickDiffPrefPage=true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,6 @@
+EXIT_PROMPT_ON_CLOSE_LAST_WINDOW=false
+TASKS_FILTERS_MIGRATE=true
+eclipse.preferences.version=1
+platformState=1380290440069
+quickStart=false
+tipsAndTricks=true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+showIntro=false
Binary file .metadata/.plugins/org.eclipse.jdt.core/invalidArchivesCache has changed
Binary file .metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache has changed
Binary file .metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<typeInfoHistroy/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<qualifiedTypeNameHistroy/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section name="Workbench">
+	<section name="ChooseWorkspaceDialogSettings">
+		<item value="330" key="DIALOG_Y_ORIGIN"/>
+		<item value="0" key="DIALOG_X_ORIGIN"/>
+	</section>
+	<section name="WORKBENCH_SETTINGS">
+		<list key="ENABLED_TRANSFERS">
+		</list>
+	</section>
+</section>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section name="Workbench">
+</section>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.ui.workbench/workbench.xml	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workbench progressCount="16" version="2.0">
+<workbenchAdvisor/>
+<window height="768" maximized="true" width="1016" x="2034" y="46">
+<fastViewData fastViewLocation="1024"/>
+<perspectiveBar>
+<itemSize x="160"/>
+</perspectiveBar>
+<coolbarLayout>
+<coolItem id="group.file" itemType="typeGroupMarker"/>
+<coolItem id="org.eclipse.ui.workbench.file" itemType="typeToolBarContribution" x="132" y="30"/>
+<coolItem id="additions" itemType="typeGroupMarker"/>
+<coolItem id="org.eclipse.debug.ui.launchActionSet" itemType="typeToolBarContribution" x="48" y="30"/>
+<coolItem id="org.eclipse.search.searchActionSet" itemType="typeToolBarContribution" x="48" y="30"/>
+<coolItem id="group.nav" itemType="typeGroupMarker"/>
+<coolItem id="org.eclipse.ui.workbench.navigate" itemType="typeToolBarContribution" x="184" y="30"/>
+<coolItem id="group.editor" itemType="typeGroupMarker"/>
+<coolItem id="group.help" itemType="typeGroupMarker"/>
+<coolItem id="org.eclipse.ui.workbench.help" itemType="typeToolBarContribution" x="-1" y="-1"/>
+</coolbarLayout>
+<page aggregateWorkingSetId="Aggregate for window 1381999860394" focus="true" label="Workspace - Resource">
+<editors>
+<editorArea activeWorkbook="DefaultEditorWorkbook">
+<info part="DefaultEditorWorkbook">
+<folder appearance="1" expanded="2">
+<presentation id="org.eclipse.ui.presentations.WorkbenchPresentationFactory"/>
+</folder>
+</info>
+</editorArea>
+</editors>
+<views>
+<view id="org.eclipse.ui.navigator.ProjectExplorer" partName="Project Explorer">
+<viewState CommonNavigator.LINKING_ENABLED="0" org.eclipse.cdt.ui.cview.groupincludes="false" org.eclipse.cdt.ui.cview.groupmacros="false" org.eclipse.cdt.ui.editor.CUChildren="true" org.eclipse.ui.navigator.resources.workingSets.showTopLevelWorkingSets="0"/>
+</view>
+<view id="org.eclipse.ui.views.TaskList" partName="Tasks">
+<viewState PRIMARY_SORT_FIELD="org.eclipse.ui.ide.completionField" categoryGroup="none" markerContentGenerator="org.eclipse.ui.ide.tasksGenerator" partName="Tasks">
+<columnWidths org.eclipse.ui.ide.completionField="40" org.eclipse.ui.ide.descriptionField="350" org.eclipse.ui.ide.locationField="105" org.eclipse.ui.ide.markerType="801" org.eclipse.ui.ide.pathField="140" org.eclipse.ui.ide.priorityField="35" org.eclipse.ui.ide.resourceField="105"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.completionField"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.priorityField"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.descriptionField"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.resourceField"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.pathField"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.locationField"/>
+<visible IMemento.internal.id="org.eclipse.ui.ide.markerType"/>
+</viewState>
+</view>
+<view id="org.eclipse.ui.views.ContentOutline" partName="Outline">
+<viewState/>
+</view>
+</views>
+<perspectives activePart="org.eclipse.ui.navigator.ProjectExplorer" activePerspective="org.eclipse.ui.resourcePerspective">
+<perspective editorAreaTrimState="2" editorAreaVisible="1" fixed="0" version="0.016">
+<descriptor class="org.eclipse.ui.internal.ide.application.ResourcePerspective" id="org.eclipse.ui.resourcePerspective" label="Resource"/>
+<alwaysOnActionSet id="org.eclipse.ui.cheatsheets.actionSet"/>
+<alwaysOnActionSet id="org.eclipse.search.searchActionSet"/>
+<alwaysOnActionSet id="org.eclipse.ui.edit.text.actionSet.annotationNavigation"/>
+<alwaysOnActionSet id="org.eclipse.ui.edit.text.actionSet.navigation"/>
+<alwaysOnActionSet id="org.eclipse.ui.edit.text.actionSet.convertLineDelimitersTo"/>
+<alwaysOnActionSet id="org.eclipse.ui.externaltools.ExternalToolsSet"/>
+<alwaysOnActionSet id="org.eclipse.ui.actionSet.keyBindings"/>
+<alwaysOnActionSet id="org.eclipse.ui.actionSet.openFiles"/>
+<alwaysOnActionSet id="org.eclipse.rse.core.search.searchActionSet"/>
+<alwaysOnActionSet id="org.eclipse.ui.NavigateActionSet"/>
+<show_view_action id="org.eclipse.ui.navigator.ProjectExplorer"/>
+<show_view_action id="org.eclipse.ui.views.BookmarkView"/>
+<show_view_action id="org.eclipse.ui.views.ContentOutline"/>
+<show_view_action id="org.eclipse.ui.views.PropertySheet"/>
+<show_view_action id="org.eclipse.ui.views.ProblemView"/>
+<show_view_action id="org.eclipse.ui.views.ProgressView"/>
+<show_view_action id="org.eclipse.ui.views.TaskList"/>
+<show_view_action id="org.eclipse.ant.ui.views.AntView"/>
+<show_view_action id="org.eclipse.pde.runtime.LogView"/>
+<new_wizard_action id="org.eclipse.ui.wizards.new.folder"/>
+<new_wizard_action id="org.eclipse.ui.wizards.new.file"/>
+<new_wizard_action id="org.eclipse.ui.editors.wizards.UntitledTextFileWizard"/>
+<perspective_action id="org.eclipse.cdt.ui.CPerspective"/>
+<perspective_action id="org.eclipse.jdt.ui.JavaPerspective"/>
+<perspective_action id="org.eclipse.jdt.ui.JavaBrowsingPerspective"/>
+<perspective_action id="org.eclipse.team.cvs.ui.cvsPerspective"/>
+<perspective_action id="org.eclipse.team.ui.TeamSynchronizingPerspective"/>
+<hide_toolbar_item_id id="org.eclipse.jdt.ui.actions.OpenProjectWizard"/>
+<hide_toolbar_item_id id="org.eclipse.ui.edit.text.toggleShowSelectedElementOnly"/>
+<view id="org.eclipse.ui.navigator.ProjectExplorer"/>
+<view id="org.eclipse.ui.views.ContentOutline"/>
+<view id="org.eclipse.ui.views.TaskList"/>
+<fastViewBars/>
+<layout>
+<mainWindow>
+<info folder="true" part="topLeft">
+<folder activePageID="org.eclipse.ui.navigator.ProjectExplorer" appearance="2" expanded="2">
+<page content="org.eclipse.ui.navigator.ProjectExplorer" label="Project Explorer"/>
+<page content="org.eclipse.ui.views.BookmarkView" label="LabelNotFound"/>
+<page content="org.eclipse.ui.views.ResourceNavigator" label="LabelNotFound"/>
+<page content="org.eclipse.team.ccvs.ui.RepositoriesView" label="LabelNotFound"/>
+<presentation id="org.eclipse.ui.presentations.WorkbenchPresentationFactory">
+<part id="0"/>
+</presentation>
+</folder>
+</info>
+<info folder="true" part="org.eclipse.ui.internal.ViewStack@2e1ed620" ratio="0.7495049" ratioLeft="757" ratioRight="253" relationship="2" relative="topLeft">
+<folder appearance="2" expanded="2">
+<page content="org.eclipse.ui.internal.introview" label="LabelNotFound"/>
+<page content="org.eclipse.help.ui.HelpView" label="LabelNotFound"/>
+<page content="org.eclipse.ui.cheatsheets.views.CheatSheetView" label="LabelNotFound"/>
+<presentation id="org.eclipse.ui.presentations.WorkbenchPresentationFactory"/>
+</folder>
+</info>
+<info part="org.eclipse.ui.editorss" ratio="0.25940594" ratioLeft="262" ratioRight="748" relationship="2" relative="topLeft"/>
+<info folder="true" part="bottomRight" ratio="0.6599064" ratioLeft="423" ratioRight="218" relationship="4" relative="org.eclipse.ui.editorss">
+<folder activePageID="org.eclipse.ui.views.TaskList" appearance="2" expanded="2">
+<page content="org.eclipse.ui.views.TaskList" label="Tasks"/>
+<page content="org.eclipse.team.ui.GenericHistoryView" label="LabelNotFound"/>
+<presentation id="org.eclipse.ui.presentations.WorkbenchPresentationFactory">
+<part id="0"/>
+</presentation>
+</folder>
+</info>
+<info folder="true" part="bottomLeft" ratio="0.49921995" ratioLeft="320" ratioRight="321" relationship="4" relative="topLeft">
+<folder activePageID="org.eclipse.ui.views.ContentOutline" appearance="2" expanded="2">
+<page content="org.eclipse.ui.views.ContentOutline" label="Outline"/>
+<page content="org.eclipse.ant.ui.views.AntView" label="LabelNotFound"/>
+<presentation id="org.eclipse.ui.presentations.WorkbenchPresentationFactory">
+<part id="0"/>
+</presentation>
+</folder>
+</info>
+</mainWindow>
+</layout>
+</perspective>
+</perspectives>
+<workingSets/>
+<navigationHistory/>
+<input factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/" type="8"/>
+</page>
+<workbenchWindowAdvisor/>
+<actionBarAdvisor/>
+<trimLayout>
+<trimArea IMemento.internal.id="128">
+<trimItem IMemento.internal.id="org.eclipse.ui.internal.WorkbenchWindow.topBar"/>
+</trimArea>
+<trimArea IMemento.internal.id="1024">
+<trimItem IMemento.internal.id="org.eclise.ui.internal.FastViewBar"/>
+<trimItem IMemento.internal.id="org.eclipse.jface.action.StatusLineManager"/>
+<trimItem IMemento.internal.id="org.eclipse.ui.internal.progress.ProgressRegion"/>
+</trimArea>
+</trimLayout>
+</window>
+<mruList/>
+</workbench>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workingSetManager>
+<workingSet aggregate="true" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1381999860395_0" label="Window Working Set" name="Aggregate for window 1381999860394"/>
+</workingSetManager>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.metadata/version.ini	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,1 @@
+org.eclipse.core.runtime=1
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>BeagleRT</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildLocation</key>
+					<value>${workspace_loc:/BBB_audio+input/Debug}</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+					<value>clean</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.settings/org.eclipse.cdt.core.prefs	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+environment/project/cdt.managedbuild.config.gnu.exe.debug.528876549/append=true
+environment/project/cdt.managedbuild.config.gnu.exe.debug.528876549/appendContributed=true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/GPIOcontrol.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,325 @@
+/*
+ * SimpleGPIO.cpp
+ *
+ * Modifications by Derek Molloy, School of Electronic Engineering, DCU
+ * www.derekmolloy.ie
+ * Almost entirely based on Software by RidgeRun:
+ *
+ * Copyright (c) 2011, RidgeRun
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the RidgeRun.
+ * 4. Neither the name of the RidgeRun 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 RIDGERUN ''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 RIDGERUN 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 "../include/GPIOcontrol.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+
+/****************************************************************
+ * gpio_setup
+ ****************************************************************/
+int gpio_setup(unsigned int gpio, int out_flag)
+{
+	/* Export the GPIO pins and set their direction */
+	if(gpio_export(gpio)) {
+		printf("Unable to export GPIO input pin\n");
+		return -1;
+	}
+	if(gpio_set_dir(gpio, out_flag)) {
+		printf("Unable to set GPIO input direction\n");
+		return -1;
+	}
+
+	return gpio_fd_open(gpio, O_RDWR);
+}
+
+/****************************************************************
+ * gpio_export
+ ****************************************************************/
+int gpio_export(unsigned int gpio)
+{
+	int fd, len, result = 0;
+	char buf[MAX_BUF];
+
+	fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/export");
+		return fd;
+	}
+
+	len = snprintf(buf, sizeof(buf), "%d", gpio);
+	if(write(fd, buf, len) < 0)
+		result = -1;
+	close(fd);
+
+	return result;
+}
+
+/****************************************************************
+ * gpio_unexport
+ ****************************************************************/
+int gpio_unexport(unsigned int gpio)
+{
+	int fd, len, result = 0;
+	char buf[MAX_BUF];
+
+	fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/export");
+		return fd;
+	}
+
+	len = snprintf(buf, sizeof(buf), "%d", gpio);
+	if(write(fd, buf, len) < 0)
+		result = -1;
+	close(fd);
+	return result;
+}
+
+/****************************************************************
+ * gpio_set_dir
+ ****************************************************************/
+int gpio_set_dir(unsigned int gpio, int out_flag)
+{
+	int fd, result = 0;
+	char buf[MAX_BUF];
+
+	snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
+
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/direction");
+		return fd;
+	}
+
+	if (out_flag == OUTPUT_PIN) {
+		if(write(fd, "out", 4) < 0)
+			result = -1;
+	}
+	else {
+		if(write(fd, "in", 3) < 0)
+			result = -1;
+	}
+
+	close(fd);
+	return result;
+}
+
+/****************************************************************
+ * gpio_set_value
+ ****************************************************************/
+int gpio_set_value(unsigned int gpio, int value)
+{
+	int fd, result = 0;
+	char buf[MAX_BUF];
+
+	snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/set-value");
+		return fd;
+	}
+
+	if (value==LOW) {
+		if(write(fd, "0", 2) < 0)
+			result = -1;
+	}
+	else {
+		if(write(fd, "1", 2) < 0)
+			result = -1;
+	}
+
+	close(fd);
+	return result;
+}
+
+/****************************************************************
+ * gpio_get_value
+ ****************************************************************/
+int gpio_get_value(unsigned int gpio, unsigned int *value)
+{
+	int fd, result = 0;
+	char buf[MAX_BUF];
+	char ch;
+
+	snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+	fd = open(buf, O_RDONLY);
+	if (fd < 0) {
+		perror("gpio/get-value");
+		return fd;
+	}
+
+	if(read(fd, &ch, 1) <= 0) {
+		result = -1;
+	}
+	else {
+		if (ch != '0') {
+		*value = 1;
+		} else {
+		*value = 0;
+		}
+	}
+
+	close(fd);
+	return result;
+}
+
+
+/****************************************************************
+ * gpio_set_edge
+ ****************************************************************/
+
+int gpio_set_edge(unsigned int gpio, char *edge)
+{
+	int fd, result = 0;
+	char buf[MAX_BUF];
+
+	snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
+
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/set-edge");
+		return fd;
+	}
+
+	if(write(fd, edge, strlen(edge) + 1) < 0)
+		result = -1;
+	close(fd);
+	return result;
+}
+
+/****************************************************************
+ * gpio_fd_open
+ ****************************************************************/
+
+int gpio_fd_open(unsigned int gpio, int writeFlag)
+{
+	int fd;
+	char buf[MAX_BUF];
+
+	snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+	fd = open(buf, writeFlag | O_NONBLOCK );
+	if (fd < 0) {
+		perror("gpio/fd_open");
+	}
+	return fd;
+}
+
+/****************************************************************
+ * gpio_fd_close
+ ****************************************************************/
+
+int gpio_fd_close(int fd)
+{
+	return close(fd);
+}
+
+/****************************************************************
+ * gpio_read
+ ****************************************************************/
+int gpio_read(int fd, unsigned int *value)
+{
+	int result = 0;
+	char ch;
+
+	if(read(fd, &ch, 1) <= 0) {
+		result = -1;
+	}
+	else {
+		if (ch != '0') {
+		*value = 1;
+		} else {
+		*value = 0;
+		}
+	}
+
+	return result;
+}
+
+/****************************************************************
+ * gpio_write
+ ****************************************************************/
+int gpio_write(int fd, int value)
+{
+	int result = 0;
+	//char buf[MAX_BUF];
+
+	if (value==LOW) {
+		if(write(fd, "0", 2) < 0)
+			result = -1;
+	}
+	else {
+		if(write(fd, "1", 2) < 0)
+			result = -1;
+	}
+
+	return result;
+}
+
+
+/****************************************************************
+ * gpio_dismiss
+ ****************************************************************/
+int gpio_dismiss(int fd, unsigned int gpio)
+{
+	close(fd);
+	gpio_unexport(gpio);
+	return 0;
+}
+
+/****************************************************************
+ * led_set_trigger
+ ****************************************************************/
+int led_set_trigger(unsigned int lednum, const char *trigger)
+{
+	// Set the trigger source for an onboard user LED
+	int fd, result = 0;
+	char buf[MAX_BUF];
+
+	snprintf(buf, sizeof(buf), SYSFS_LED_DIR "/beaglebone:green:usr%d/trigger", lednum);
+
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/led-set-trigger");
+		return fd;
+	}
+
+	if(write(fd, trigger, strlen(trigger) + 1) < 0)
+		result = -1;
+
+	close(fd);
+	return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/I2c_Codec.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,286 @@
+/*
+ * I2c_Codec.cpp
+ *
+ * Handle writing the registers to the TLV320AIC310x
+ * series audio codecs, used on the BeagleBone Audio Cape.
+ * This code is designed to bypass the ALSA driver and
+ * configure the codec directly in a sensible way. It
+ * is complemented by code running on the PRU which uses
+ * the McASP serial port to transfer audio data.
+ *
+ *  Created on: May 25, 2014
+ *      Author: Andrew McPherson
+ */
+
+#include "../include/I2c_Codec.h"
+
+I2c_Codec::I2c_Codec()
+: running(false), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0)
+{}
+
+// This method initialises the audio codec to its default state
+int I2c_Codec::initCodec()
+{
+	// Write the reset register of the codec
+	if(writeRegister(0x01, 0x80)) // Software reset register
+	{
+		cout << "Failed to reset codec\n";
+		return 1;
+	}
+
+	// Wait for codec to process the reset (for safety)
+	usleep(5000);
+
+	return 0;
+}
+
+// Tell the codec to start generating audio
+// See the TLV320AIC3106 datasheet for full details of the registers
+// The dual_rate flag, when true, runs the codec at 88.2kHz; otherwise
+// it runs at 44.1kHz
+int I2c_Codec::startAudio(int dual_rate)
+{
+	if(writeRegister(0x02, 0x00))	// Codec sample rate register: fs_ref / 1
+		return 1;
+	if(writeRegister(0x03, 0x91))	// PLL register A: enable
+		return 1;
+	if(writeRegister(0x04, 0x1C))	// PLL register B
+		return 1;
+	if(writeRegister(0x05, 0x52))	// PLL register C
+		return 1;
+	if(writeRegister(0x06, 0x40))	// PLL register D
+		return 1;
+	if(dual_rate) {
+		if(writeRegister(0x07, 0xEA))	// Codec datapath register: 44.1kHz; dual rate; standard datapath
+			return 1;
+	}
+	else {
+		if(writeRegister(0x07, 0x8A))	// Codec datapath register: 44.1kHz; std rate; standard datapath
+			return 1;
+	}
+	if(writeRegister(0x08, 0xC0))	// Audio serial control register A: BLCK, WCLK outputs
+		return 1;
+	if(writeRegister(0x09, 0x40))	// Audio serial control register B: DSP mode, word len 16 bits
+		return 1;
+	if(writeRegister(0x0A, 0x00))	// Audio serial control register C: 0 bit offset
+		return 1;
+	if(writeRegister(0x0B, 0x01))	// Audio codec overflow flag register: PLL R = 1
+		return 1;
+	if(writeRegister(0x0C, 0x00))	// Digital filter register: disabled
+		return 1;
+	if(writeRegister(0x0D, 0x00))	// Headset / button press register A: disabled
+		return 1;
+	if(writeRegister(0x0E, 0x00))	// Headset / button press register B: disabled
+		return 1;
+	if(writeRegister(0x0F, 0x20))	// Left ADC PGA gain control: not muted; 0x20 = 16dB
+		return 1;
+	if(writeRegister(0x10, 0x20))	// Right ADC PGA gain control: not muted; 0x20 = 16dB
+		return 1;
+
+	if(writeRegister(0x25, 0xC0))	// DAC power/driver register: DAC power on (left and right)
+		return 1;
+	if(writeRegister(0x26, 0x04))	// High power output driver register: Enable short circuit protection
+		return 1;
+	if(writeRegister(0x28, 0x02))	// High power output stage register: disable soft stepping
+		return 1;
+
+	if(writeRegister(0x52, 0x80))	// DAC_L1 to LEFT_LOP volume control: routed, volume 0dB
+		return 1;
+	if(writeRegister(0x5C, 0x80))	// DAC_R1 to RIGHT_LOP volume control: routed, volume 0dB
+		return 1;
+
+	if(writeHPVolumeRegisters())	// Send DAC to high-power outputs
+		return 1;
+
+	if(writeRegister(0x66, 0x02))			// Clock generation control register: use MCLK, PLL N = 2
+		return 1;
+
+	if(writeRegister(0x33, 0x0D))	// HPLOUT output level control: output level = 0dB, not muted, powered up
+		return 1;
+	if(writeRegister(0x41, 0x0D))	// HPROUT output level control: output level = 0dB, not muted, powered up
+		return 1;
+	if(writeRegister(0x56, 0x09))	// LEFT_LOP output level control: 0dB, not muted, powered up
+		return 1;
+	if(writeRegister(0x5D, 0x09))	// RIGHT_LOP output level control: 0dB, not muted, powered up
+		return 1;
+
+	if(writeDACVolumeRegisters(false))	// Unmute and set volume
+		return 1;
+
+	if(writeRegister(0x65, 0x00))	// GPIO control register B: disabled; codec uses PLLDIV_OUT
+		return 1;
+
+	if(writeADCVolumeRegisters(false))	// Unmute and set ADC volume
+		return 1;
+
+	running = true;
+	return 0;
+}
+
+// Set the volume of the DAC output
+int I2c_Codec::setDACVolume(int halfDbSteps)
+{
+	dacVolumeHalfDbs = halfDbSteps;
+	if(running)
+		return writeDACVolumeRegisters(false);
+
+	return 0;
+}
+
+// Set the volume of the DAC output
+int I2c_Codec::setADCVolume(int halfDbSteps)
+{
+	adcVolumeHalfDbs = halfDbSteps;
+	if(running)
+		return writeADCVolumeRegisters(false);
+
+	return 0;
+}
+
+// Update the DAC volume control registers
+int I2c_Codec::writeDACVolumeRegisters(bool mute)
+{
+	int volumeBits = 0;
+
+	if(dacVolumeHalfDbs < 0) { // Volume is specified in half-dBs with 0 as full scale
+		volumeBits = -dacVolumeHalfDbs;
+		if(volumeBits > 127)
+			volumeBits = 127;
+	}
+
+	if(mute) {
+		if(writeRegister(0x2B, volumeBits | 0x80))	// Left DAC volume control: muted
+			return 1;
+		if(writeRegister(0x2C, volumeBits | 0x80))	// Right DAC volume control: muted
+			return 1;
+	}
+	else {
+		if(writeRegister(0x2B, volumeBits))	// Left DAC volume control: not muted
+			return 1;
+		if(writeRegister(0x2C, volumeBits))	// Right DAC volume control: not muted
+			return 1;
+	}
+
+	return 0;
+}
+
+// Update the ADC volume control registers
+int I2c_Codec::writeADCVolumeRegisters(bool mute)
+{
+	int volumeBits = 0;
+
+	// Volume is specified in half-dBs with 0 as full scale
+	// The codec uses 1.5dB steps so we divide this number by 3
+	if(adcVolumeHalfDbs < 0) {
+		volumeBits = -adcVolumeHalfDbs / 3;
+		if(volumeBits > 8)
+			volumeBits = 8;
+	}
+
+	if(mute) {
+		if(writeRegister(0x13, 0x00))		// Line1L to Left ADC control register: power down
+			return 1;
+		if(writeRegister(0x16, 0x00))		// Line1R to Right ADC control register: power down
+			return 1;
+	}
+	else {
+		if(writeRegister(0x13, 0x7C))	// Line1L disabled; left ADC powered up with soft step
+			return 1;
+		if(writeRegister(0x16, 0x7C))	// Line1R disabled; right ADC powered up with soft step
+			return 1;
+		if(writeRegister(0x11, (volumeBits << 4) | 0x0F))	// Line2L connected to left ADC
+			return 1;
+		if(writeRegister(0x12, volumeBits | 0xF0))		    // Line2R connected to right ADC
+			return 1;
+	}
+
+	return 0;
+}
+
+// Set the volume of the headphone output
+int I2c_Codec::setHPVolume(int halfDbSteps)
+{
+	hpVolumeHalfDbs = halfDbSteps;
+	if(running)
+		return writeHPVolumeRegisters();
+
+	return 0;
+}
+
+
+// Update the headphone volume control registers
+int I2c_Codec::writeHPVolumeRegisters()
+{
+	int volumeBits = 0;
+
+	if(hpVolumeHalfDbs < 0) { // Volume is specified in half-dBs with 0 as full scale
+		volumeBits = -hpVolumeHalfDbs;
+		if(volumeBits > 127)
+			volumeBits = 127;
+	}
+
+	if(writeRegister(0x2F, volumeBits | 0x80)) // DAC_L1 to HPLOUT register: route to HPLOUT, volume 0dB
+		return 1;
+	if(writeRegister(0x40, volumeBits | 0x80)) // DAC_R1 to HPROUT register: route to HPROUT, volume 0dB
+		return 1;
+
+	return 0;
+}
+
+// This tells the codec to stop generating audio and mute the outputs
+int I2c_Codec::stopAudio()
+{
+	if(writeDACVolumeRegisters(true))	// Mute the DACs
+		return 1;
+	if(writeADCVolumeRegisters(true))	// Mute the ADCs
+		return 1;
+
+	usleep(10000);
+
+	if(writeRegister(0x33, 0x0C))		// HPLOUT output level register: muted
+		return 1;
+	if(writeRegister(0x41, 0x0C))		// HPROUT output level register: muted
+		return 1;
+	if(writeRegister(0x56, 0x08))		// LEFT_LOP output level control: muted
+		return 1;
+	if(writeRegister(0x5D, 0x08))		// RIGHT_LOP output level control: muted
+		return 1;
+	if(writeRegister(0x25, 0x00))		// DAC power/driver register: power off
+		return 1;
+	if(writeRegister(0x03, 0x11))		// PLL register A: disable
+		return 1;
+	if(writeRegister(0x01, 0x80))		// Reset codec to defaults
+		return 1;
+
+	running = false;
+	return 0;
+}
+
+// Write a specific register on the codec
+int I2c_Codec::writeRegister(unsigned int reg, unsigned int value)
+{
+	char buf[2] = { reg & 0xFF, value & 0xFF };
+
+	if(write(i2C_file, buf, 2) != 2)
+	{
+		cout << "Failed to write register " << reg << " on codec\n";
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int I2c_Codec::readI2C()
+{
+	// Nothing to do here, we only write the registers
+	return 0;
+}
+
+
+I2c_Codec::~I2c_Codec()
+{
+	if(running)
+		stopAudio();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/PRU.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,469 @@
+/*
+ * PRU.cpp
+ *
+ * Code for communicating with the Programmable Realtime Unit (PRU)
+ * on the BeagleBone AM335x series processors. The PRU loads and runs
+ * a separate code image compiled from an assembly file. Here it is
+ * used to handle audio and SPI ADC/DAC data.
+ *
+ * This code is specific to the PRU code in the assembly file; for example,
+ * it uses certain GPIO resources that correspond to that image.
+ *
+ *  Created on: May 27, 2014
+ *      Author: andrewm
+ */
+
+#include "../include/PRU.h"
+#include "../include/prussdrv.h"
+#include "../include/pruss_intc_mapping.h"
+#include "../include/GPIOcontrol.h"
+#include "../include/render.h"
+
+#include <iostream>
+#include <stdlib.h>
+#include <cstdio>
+#include <cerrno>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+// Xenomai-specific includes
+#include <sys/mman.h>
+#include <native/task.h>
+#include <native/timer.h>
+#include <rtdk.h>
+
+using namespace std;
+
+#define PRU_MEM_MCASP_OFFSET 0x2000  // Offset within PRU-SHARED RAM
+#define PRU_MEM_MCASP_LENGTH 0x2000  // Length of McASP memory, in bytes
+#define PRU_MEM_DAC_OFFSET 0x0     // Offset within PRU0 RAM
+#define PRU_MEM_DAC_LENGTH 0x2000  // Length of ADC+DAC memory, in bytes
+#define PRU_MEM_COMM_OFFSET 0x0    // Offset within PRU-SHARED RAM
+
+#define PRU_SHOULD_STOP 	0
+#define PRU_CURRENT_BUFFER  1
+#define PRU_BUFFER_FRAMES   2
+#define PRU_SHOULD_SYNC     3
+#define PRU_SYNC_ADDRESS    4
+#define PRU_SYNC_PIN_MASK   5
+#define PRU_LED_ADDRESS		6
+#define PRU_LED_PIN_MASK	7
+#define PRU_FRAME_COUNT		8
+#define PRU_USE_SPI			9
+
+#define PRU_SAMPLE_INTERVAL_NS 45351	// 22050Hz per SPI sample = 45.351us
+
+#define GPIO0_ADDRESS 		0x44E07000
+#define GPIO1_ADDRESS 		0x4804C000
+#define GPIO_SIZE			0x198
+#define GPIO_CLEARDATAOUT 	(0x190 / 4)
+#define GPIO_SETDATAOUT 	(0x194 / 4)
+
+#define TEST_PIN_GPIO_BASE	GPIO0_ADDRESS	// Use GPIO0(31) for debugging
+#define TEST_PIN_MASK		(1 << 31)
+#define TEST_PIN2_MASK		(1 << 26)
+
+#define USERLED3_GPIO_BASE  GPIO1_ADDRESS // GPIO1(24) is user LED 3
+#define USERLED3_PIN_MASK   (1 << 24)
+
+const unsigned int PRU::kPruGPIODACSyncPin = 5;	// GPIO0(5); P9-17
+const unsigned int PRU::kPruGPIOADCSyncPin = 48; // GPIO1(16); P9-15
+
+const unsigned int PRU::kPruGPIOTestPin = 60;	// GPIO1(28); P9-12
+const unsigned int PRU::kPruGPIOTestPin2 = 31;	// GPIO0(31); P9-13
+const unsigned int PRU::kPruGPIOTestPin3 = 26;	// GPIO0(26); P8-14
+
+extern int gShouldStop;
+extern int gRTAudioVerbose;
+
+// Constructor: specify a PRU number (0 or 1)
+PRU::PRU()
+: pru_number(0), running(false), spi_enabled(false), gpio_enabled(false), led_enabled(false),
+  gpio_test_pin_enabled(false), xenomai_gpio_fd(-1), xenomai_gpio(0)
+{
+
+}
+
+// Destructor
+PRU::~PRU()
+{
+	if(running)
+		disable();
+	if(gpio_enabled)
+		cleanupGPIO();
+	if(xenomai_gpio_fd >= 0)
+		close(xenomai_gpio_fd);
+}
+
+// Prepare the GPIO pins needed for the PRU
+// If include_test_pin is set, the GPIO output
+// is also prepared for an output which can be
+// viewed on a scope. If include_led is set,
+// user LED 3 on the BBB is taken over by the PRU
+// to indicate activity
+int PRU::prepareGPIO(int use_spi, int include_test_pin, int include_led)
+{
+	if(use_spi) {
+		// Prepare DAC CS/ pin: output, high to begin
+		if(gpio_export(kPruGPIODACSyncPin)) {
+			if(gRTAudioVerbose)
+				cout << "Warning: couldn't export DAC sync pin\n";
+		}
+		if(gpio_set_dir(kPruGPIODACSyncPin, OUTPUT_PIN)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set direction on DAC sync pin\n";
+			return -1;
+		}
+		if(gpio_set_value(kPruGPIODACSyncPin, HIGH)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set value on DAC sync pin\n";
+			return -1;
+		}
+
+		// Prepare ADC CS/ pin: output, high to begin
+		if(gpio_export(kPruGPIOADCSyncPin)) {
+			if(gRTAudioVerbose)
+				cout << "Warning: couldn't export ADC sync pin\n";
+		}
+		if(gpio_set_dir(kPruGPIOADCSyncPin, OUTPUT_PIN)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set direction on ADC sync pin\n";
+			return -1;
+		}
+		if(gpio_set_value(kPruGPIOADCSyncPin, HIGH)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set value on ADC sync pin\n";
+			return -1;
+		}
+
+		spi_enabled = true;
+	}
+
+	if(include_test_pin) {
+		// Prepare GPIO test output (for debugging), low to begin
+		if(gpio_export(kPruGPIOTestPin)) {
+			if(gRTAudioVerbose)
+				cout << "Warning: couldn't export GPIO test pin\n";
+		}
+		if(gpio_set_dir(kPruGPIOTestPin, OUTPUT_PIN)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set direction on GPIO test pin\n";
+			return -1;
+		}
+		if(gpio_set_value(kPruGPIOTestPin, LOW)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set value on GPIO test pin\n";
+			return -1;
+		}
+
+		if(gpio_export(kPruGPIOTestPin2)) {
+			if(gRTAudioVerbose)
+				cout << "Warning: couldn't export GPIO test pin 2\n";
+		}
+		if(gpio_set_dir(kPruGPIOTestPin2, OUTPUT_PIN)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set direction on GPIO test pin 2\n";
+			return -1;
+		}
+		if(gpio_set_value(kPruGPIOTestPin2, LOW)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set value on GPIO test pin 2\n";
+			return -1;
+		}
+
+		if(gpio_export(kPruGPIOTestPin3)) {
+			if(gRTAudioVerbose)
+				cout << "Warning: couldn't export GPIO test pin 3\n";
+		}
+		if(gpio_set_dir(kPruGPIOTestPin3, OUTPUT_PIN)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set direction on GPIO test pin 3\n";
+			return -1;
+		}
+		if(gpio_set_value(kPruGPIOTestPin3, LOW)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set value on GPIO test pin 3\n";
+			return -1;
+		}
+		gpio_test_pin_enabled = true;
+	}
+
+	if(include_led) {
+		// Turn off system function for LED3 so it can be reused by PRU
+		led_set_trigger(3, "none");
+		led_enabled = true;
+	}
+
+	gpio_enabled = true;
+
+	return 0;
+}
+
+// Clean up the GPIO at the end
+void PRU::cleanupGPIO()
+{
+	if(!gpio_enabled)
+		return;
+	if(spi_enabled) {
+		gpio_unexport(kPruGPIODACSyncPin);
+		gpio_unexport(kPruGPIOADCSyncPin);
+	}
+	if(gpio_test_pin_enabled) {
+		gpio_unexport(kPruGPIOTestPin);
+		gpio_unexport(kPruGPIOTestPin2);
+		gpio_unexport(kPruGPIOTestPin3);
+	}
+	if(led_enabled) {
+		// Set LED back to default eMMC status
+		// TODO: make it go back to its actual value before this program,
+		// rather than the system default
+		led_set_trigger(3, "mmc1");
+	}
+
+	gpio_enabled = gpio_test_pin_enabled = false;
+}
+
+// Initialise and open the PRU
+int PRU::initialise(int pru_num, int frames_per_buffer, bool xenomai_test_pin)
+{
+	uint32_t *pruMem = 0;
+
+	if(!gpio_enabled) {
+		rt_printf("initialise() called before GPIO enabled\n");
+		return 1;
+	}
+
+	pru_number = pru_num;
+
+    /* Initialize structure used by prussdrv_pruintc_intc   */
+    /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */
+    tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
+
+    /* Allocate and initialize memory */
+    prussdrv_init();
+    if(prussdrv_open(PRU_EVTOUT_0)) {
+    	rt_printf("Failed to open PRU driver\n");
+    	return 1;
+    }
+
+    /* Map PRU's INTC */
+    prussdrv_pruintc_init(&pruss_intc_initdata);
+
+    spi_buffer_frames = frames_per_buffer;
+    audio_buffer_frames = spi_buffer_frames * 2;
+
+    /* Map PRU memory to pointers */
+	prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem);
+    pru_buffer_comm = (uint32_t *)&pruMem[PRU_MEM_COMM_OFFSET/sizeof(uint32_t)];
+	pru_buffer_audio_dac = (int16_t *)&pruMem[PRU_MEM_MCASP_OFFSET/sizeof(uint32_t)];
+
+	/* ADC memory starts 2(ch)*2(buffers)*2(samples/spi)*bufsize samples later */
+	pru_buffer_audio_adc = &pru_buffer_audio_dac[8 * spi_buffer_frames];
+
+	if(spi_enabled) {
+		prussdrv_map_prumem (pru_number == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void **)&pruMem);
+		pru_buffer_spi_dac = (uint16_t *)&pruMem[PRU_MEM_DAC_OFFSET/sizeof(uint32_t)];
+
+		/* ADC memory starts after 8(ch)*2(buffers)*bufsize samples */
+		pru_buffer_spi_adc = &pru_buffer_spi_dac[16 * spi_buffer_frames];
+	}
+	else {
+		pru_buffer_spi_dac = pru_buffer_spi_adc = 0;
+	}
+
+    /* Set up flags */
+    pru_buffer_comm[PRU_SHOULD_STOP] = 0;
+    pru_buffer_comm[PRU_CURRENT_BUFFER] = 0;
+    pru_buffer_comm[PRU_BUFFER_FRAMES] = spi_buffer_frames;
+    pru_buffer_comm[PRU_SHOULD_SYNC] = 0;
+    pru_buffer_comm[PRU_SYNC_ADDRESS] = 0;
+    pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0;
+    if(led_enabled) {
+    	pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE;
+    	pru_buffer_comm[PRU_LED_PIN_MASK] = USERLED3_PIN_MASK;
+    }
+    else {
+    	pru_buffer_comm[PRU_LED_ADDRESS] = 0;
+    	pru_buffer_comm[PRU_LED_PIN_MASK] = 0;
+    }
+    if(spi_enabled) {
+    	pru_buffer_comm[PRU_USE_SPI] = 1;
+    }
+    else {
+    	pru_buffer_comm[PRU_USE_SPI] = 0;
+    }
+
+    /* Clear ADC and DAC memory */
+    if(spi_enabled) {
+		for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++)
+			pru_buffer_spi_dac[i] = 0;
+    }
+	for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++)
+		pru_buffer_audio_dac[i] = 0;
+
+	/* If using GPIO test pin for Xenomai (for debugging), initialise the pointer now */
+	if(xenomai_test_pin && xenomai_gpio_fd < 0) {
+		xenomai_gpio_fd = open("/dev/mem", O_RDWR);
+		if(xenomai_gpio_fd < 0)
+			rt_printf("Unable to open /dev/mem for GPIO test pin\n");
+		else {
+			xenomai_gpio = (uint32_t *)mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, xenomai_gpio_fd, TEST_PIN_GPIO_BASE);
+			if(xenomai_gpio == MAP_FAILED) {
+				rt_printf("Unable to map GPIO address for test pin\n");
+				xenomai_gpio = 0;
+				close(xenomai_gpio_fd);
+				xenomai_gpio_fd = -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+// Run the code image in the specified file
+int PRU::start(char * const filename)
+{
+	/* Clear any old interrupt */
+	prussdrv_pru_clear_event(pru_number == 0 ? PRU0_ARM_INTERRUPT : PRU1_ARM_INTERRUPT);
+
+    /* Load and execute binary on PRU */
+    if(prussdrv_exec_program(pru_number, filename)) {
+    	rt_printf("Failed to execute PRU code from %s\n", filename);
+    	return 1;
+    }
+
+    running = true;
+    return 0;
+}
+
+// Main loop to read and write data from/to PRU
+void PRU::loop()
+{
+	// Polling interval is 1/4 of the period
+	RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * spi_buffer_frames / 4;
+	float *audioInBuffer, *audioOutBuffer;
+
+	audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
+	audioOutBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
+
+	if(audioInBuffer == 0 || audioOutBuffer == 0) {
+		rt_printf("Error: couldn't allocated audio buffers\n");
+		return;
+	}
+
+	while(!gShouldStop) {
+		// Wait for PRU to move to buffer 1
+		while(pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 && !gShouldStop) {
+			rt_task_sleep(sleepTime);
+		}
+		if(gShouldStop)
+			break;
+
+		if(xenomai_gpio != 0) {
+			// Set the test pin high
+			xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
+		}
+
+		// Render from/to buffer 0
+
+		// Convert short (16-bit) samples to float
+		for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
+			audioInBuffer[n] = (float)pru_buffer_audio_adc[n] / 32768.0;
+
+		if(spi_enabled)
+			render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
+					pru_buffer_spi_adc, pru_buffer_spi_dac);
+		else
+			render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
+
+		// Convert float back to short
+		for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
+			int out = audioOutBuffer[n] * 32768.0;
+			if(out < -32768) out = -32768;
+			else if(out > 32767) out = 32767;
+			pru_buffer_audio_dac[n] = (int16_t)out;
+		}
+
+		if(xenomai_gpio != 0) {
+			// Set the test pin high
+			xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
+		}
+
+		// Wait for PRU to move to buffer 0
+		while(pru_buffer_comm[PRU_CURRENT_BUFFER] != 0 && !gShouldStop) {
+			rt_task_sleep(sleepTime);
+		}
+
+		if(gShouldStop)
+			break;
+
+		if(xenomai_gpio != 0) {
+			// Set the test pin high
+			xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
+		}
+
+		// Render from/to buffer 1
+
+		// Convert short (16-bit) samples to float
+		for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
+			audioInBuffer[n] = (float)pru_buffer_audio_adc[n + audio_buffer_frames * 2] / 32768.0;
+
+		if(spi_enabled)
+			render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
+					&pru_buffer_spi_adc[spi_buffer_frames * 8], &pru_buffer_spi_dac[spi_buffer_frames * 8]);
+		else
+			render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
+
+		// Convert float back to short
+		for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
+			int out = audioOutBuffer[n] * 32768.0;
+			if(out < -32768) out = -32768;
+			else if(out > 32767) out = 32767;
+			pru_buffer_audio_dac[n + audio_buffer_frames * 2] = (int16_t)out;
+		}
+
+		if(xenomai_gpio != 0) {
+			// Set the test pin high
+			xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
+		}
+	}
+
+	// Tell PRU to stop
+	pru_buffer_comm[PRU_SHOULD_STOP] = 1;
+
+	free(audioInBuffer);
+	free(audioOutBuffer);
+}
+
+// Wait for an interrupt from the PRU indicate it is finished
+void PRU::waitForFinish()
+{
+	if(!running)
+		return;
+    prussdrv_pru_wait_event (PRU_EVTOUT_0);
+    prussdrv_pru_clear_event(pru_number == 0 ? PRU0_ARM_INTERRUPT : PRU1_ARM_INTERRUPT);
+}
+
+// Turn off the PRU when done
+void PRU::disable()
+{
+    /* Disable PRU and close memory mapping*/
+    prussdrv_pru_disable(pru_number);
+    prussdrv_exit();
+	running = false;
+}
+
+// Debugging
+void PRU::setGPIOTestPin()
+{
+	if(!xenomai_gpio)
+		return;
+	xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN2_MASK;
+}
+
+void PRU::clearGPIOTestPin()
+{
+	if(!xenomai_gpio)
+		return;
+	xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN2_MASK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/RTAudio.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,325 @@
+/*
+ *  RTAudio.cpp
+ *
+ *  Central control code for hard real-time audio on BeagleBone Black
+ *  using PRU and Xenomai Linux extensions. This code began as part
+ *  of the Hackable Instruments project (EPSRC) at Queen Mary University
+ *  of London, 2013-14.
+ *
+ *  (c) 2014 Victor Zappi and Andrew McPherson
+ *  Queen Mary University of London
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <math.h>
+#include <iostream>
+#include <assert.h>
+#include <vector>
+
+// Xenomai-specific includes
+#include <sys/mman.h>
+#include <native/task.h>
+#include <native/timer.h>
+#include <rtdk.h>
+
+#include "../include/RTAudio.h"
+#include "../include/PRU.h"
+#include "../include/I2c_Codec.h"
+#include "../include/render.h"
+#include "../include/GPIOcontrol.h"
+
+using namespace std;
+
+// Data structure to keep track of auxiliary tasks we
+// can schedule
+typedef struct {
+	RT_TASK task;
+	void (*function)(void);
+	char *name;
+	int priority;
+} InternalAuxiliaryTask;
+
+const char gRTAudioThreadName[] = "beaglert-audio";
+const char gRTCalculationThreadNameMedium[] = "dbox-calculation-medium";
+const char gRTCalculationThreadNameLow[] = "dbox-calculation-low";
+
+// Real-time tasks and objects
+RT_TASK gRTAudioThread;
+PRU *gPRU = 0;
+I2c_Codec *gAudioCodec = 0;
+
+vector<InternalAuxiliaryTask*> gAuxTasks;
+
+// Flag which tells the audio task to stop
+bool gShouldStop = false;
+
+// general settings
+int gRTAudioVerbose = 0;   						// Verbosity level for debugging
+char gPRUFilename[256]	 = "pru_rtaudio.bin"; 	// path to PRU binary file
+int gAmplifierMutePin = -1;
+
+
+// initAudio() prepares the infrastructure for running PRU-based real-time
+// audio, but does not actually start the calculations.
+// periodSize indicates the number of _sensor_ frames per period: the audio period size
+// is twice this value. In total, the audio latency in frames will be 4*periodSize,
+// plus any latency inherent in the ADCs and DACs themselves.
+// useMatrix indicates whether to use the ADC and DAC or just the audio codec.
+// userData is an opaque pointer which will be passed through to the initialise_render()
+// function for application-specific use
+//
+// Returns 0 on success.
+
+int initAudio(int periodSize, int useMatrix,
+			  void *userData,
+			  int codecI2CAddress, int ampMutePin)
+{
+	rt_print_auto_init(1);
+	if(gRTAudioVerbose == 1)
+		rt_printf("Running with Xenomai\n");
+
+	if(gRTAudioVerbose == 1)
+		cout << "---------------->Init Audio Thread" << endl;
+
+	// Prepare GPIO pins for amplifier mute and status LED
+	if(ampMutePin >= 0) {
+		gAmplifierMutePin = ampMutePin;
+
+		if(gpio_export(ampMutePin)) {
+			if(gRTAudioVerbose)
+				cout << "Warning: couldn't export amplifier mute pin\n";
+		}
+		if(gpio_set_dir(ampMutePin, OUTPUT_PIN)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set direction on amplifier mute pin\n";
+			return -1;
+		}
+		if(gpio_set_value(ampMutePin, LOW)) {
+			if(gRTAudioVerbose)
+				cout << "Couldn't set value on amplifier mute pin\n";
+			return -1;
+		}
+	}
+
+	// Use PRU for audio
+	gPRU = new PRU();
+	gAudioCodec = new I2c_Codec();
+
+	if(gPRU->prepareGPIO(useMatrix, 1, 1)) {
+		cout << "Error: unable to prepare GPIO for PRU audio\n";
+		return 1;
+	}
+	if(gPRU->initialise(0, periodSize, true)) {
+		cout << "Error: unable to initialise PRU\n";
+		return 1;
+	}
+	if(gAudioCodec->initI2C_RW(2, codecI2CAddress, -1)) {
+		cout << "Unable to open codec I2C\n";
+		return 1;
+	}
+	if(gAudioCodec->initCodec()) {
+		cout << "Error: unable to initialise audio codec\n";
+		return 1;
+	}
+	gAudioCodec->setDACVolume(0);	// Set the DAC volume to full-scale
+	gAudioCodec->setHPVolume(-12);	// Headphones 6dB down
+	gAudioCodec->setADCVolume(-12);	// Set the ADC volume to 6dB down
+
+	if(!initialise_render(2, useMatrix ? periodSize : 0, periodSize * 2, 22050.0, 44100.0, userData)) {
+		cout << "Couldn't initialise audio rendering\n";
+		return 1;
+	}
+
+	return 0;
+}
+
+// audioLoop() is the main function which starts the PRU audio code
+// and then transfers control to the PRU object. The PRU object in
+// turn will call the audio render() callback function every time
+// there is new data to process.
+
+void audioLoop(void *)
+{
+	if(gRTAudioVerbose==1)
+		rt_printf("_________________Audio Thread!\n");
+
+	// PRU audio
+	assert(gAudioCodec != 0 && gPRU != 0);
+
+	if(gAudioCodec->startAudio(0)) {
+		rt_printf("Error: unable to start I2C audio codec\n");
+		gShouldStop = 1;
+	}
+	else {
+		if(gPRU->start(gPRUFilename)) {
+			rt_printf("Error: unable to start PRU from file %s\n", gPRUFilename);
+			gShouldStop = 1;
+		}
+		else {
+			// All systems go. Run the loop; it will end when gShouldStop is set to 1
+			// First unmute the amplifier
+			if(gpio_set_value(gAmplifierMutePin, HIGH)) {
+				if(gRTAudioVerbose)
+					rt_printf("Warning: couldn't set value (high) on amplifier mute pin\n");
+			}
+
+			gPRU->loop();
+
+			// Now clean up
+			// gPRU->waitForFinish();
+			gPRU->disable();
+			gAudioCodec->stopAudio();
+			gPRU->cleanupGPIO();
+		}
+	}
+
+	if(gRTAudioVerbose == 1)
+		rt_printf("audio thread ended\n");
+}
+
+// Create a calculation loop which can run independently of the audio, at a different
+// (equal or lower) priority. Audio priority is 99; priority should be generally be less than this.
+// Returns an (opaque) pointer to the created task on success; 0 on failure
+AuxiliaryTask createAuxiliaryTaskLoop(void (*functionToCall)(void), int priority, const char *name)
+{
+	InternalAuxiliaryTask *newTask = (InternalAuxiliaryTask*)malloc(sizeof(InternalAuxiliaryTask));
+
+	// Attempt to create the task
+	if(rt_task_create(&(newTask->task), name, 0, priority, T_JOINABLE | T_FPU)) {
+		  cout << "Error: unable to create auxiliary task " << name << endl;
+		  free(newTask);
+		  return 0;
+	}
+
+	// Populate the rest of the data structure and store it in the vector
+	newTask->function = functionToCall;
+	newTask->name = strdup(name);
+	newTask->priority = priority;
+
+	gAuxTasks.push_back(newTask);
+
+	return (AuxiliaryTask)newTask;
+}
+
+// Schedule a previously created auxiliary task. It will run when the priority rules next
+// allow it to be scheduled.
+void scheduleAuxiliaryTask(AuxiliaryTask task)
+{
+	InternalAuxiliaryTask *taskToSchedule = (InternalAuxiliaryTask *)task;
+
+	rt_task_resume(&taskToSchedule->task);
+}
+
+// Calculation loop that can be used for other tasks running at a lower
+// priority than the audio thread. Simple wrapper for Xenomai calls.
+// Treat the argument as containing the task structure
+void auxiliaryTaskLoop(void *taskStruct)
+{
+	// Get function to call from the argument
+	void (*auxiliary_function)(void) = ((InternalAuxiliaryTask *)taskStruct)->function;
+	const char *name = ((InternalAuxiliaryTask *)taskStruct)->name;
+
+	// Wait for a notification
+	rt_task_suspend(NULL);
+
+	while(!gShouldStop) {
+		// Then run the calculations
+		auxiliary_function();
+
+		// Wait for a notification
+		rt_task_suspend(NULL);
+	}
+
+	if(gRTAudioVerbose == 1)
+		rt_printf("auxiliary task %s ended\n", name);
+}
+
+// startAudio() should be called only after initAudio() successfully completes.
+// It launches the real-time Xenomai task which runs the audio loop. Returns 0
+// on success.
+
+int startAudio()
+{
+	// Create audio thread with the highest priority
+	if(rt_task_create(&gRTAudioThread, gRTAudioThreadName, 0, 99, T_JOINABLE | T_FPU)) {
+		  cout << "Error: unable to create Xenomai audio thread" << endl;
+		  return -1;
+	}
+
+	// Start all RT threads
+	if(rt_task_start(&gRTAudioThread, &audioLoop, 0)) {
+		  cout << "Error: unable to start Xenomai audio thread" << endl;
+		  return -1;
+	}
+
+	// The user may have created other tasks. Start those also.
+	vector<InternalAuxiliaryTask*>::iterator it;
+	for(it = gAuxTasks.begin(); it != gAuxTasks.end(); it++) {
+		InternalAuxiliaryTask *taskStruct = *it;
+
+		if(rt_task_start(&(taskStruct->task), &auxiliaryTaskLoop, taskStruct)) {
+			cerr << "Error: unable to start Xenomai task " << taskStruct->name << endl;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+// Stop the PRU-based audio from running and wait
+// for the tasks to complete before returning.
+
+void stopAudio()
+{
+	// Tell audio thread to stop (if this hasn't been done already)
+	gShouldStop = true;
+
+	// Now wait for threads to respond and actually stop...
+	rt_task_join(&gRTAudioThread);
+
+	// Stop all the auxiliary threads too
+	vector<InternalAuxiliaryTask*>::iterator it;
+	for(it = gAuxTasks.begin(); it != gAuxTasks.end(); it++) {
+		InternalAuxiliaryTask *taskStruct = *it;
+
+		// Wake up each thread and join it
+		rt_task_resume(&(taskStruct->task));
+		rt_task_join(&(taskStruct->task));
+	}
+}
+
+// Free any resources associated with PRU real-time audio
+void cleanupAudio()
+{
+	cleanup_render();
+
+	// Clean up the auxiliary tasks
+	vector<InternalAuxiliaryTask*>::iterator it;
+	for(it = gAuxTasks.begin(); it != gAuxTasks.end(); it++) {
+		InternalAuxiliaryTask *taskStruct = *it;
+
+		// Free the name string and the struct itself
+		free(taskStruct->name);
+		free(taskStruct);
+	}
+	gAuxTasks.clear();
+
+	if(gPRU != 0)
+		delete gPRU;
+	if(gAudioCodec != 0)
+		delete gAudioCodec;
+
+	if(gAmplifierMutePin >= 0)
+		gpio_unexport(gAmplifierMutePin);
+	gAmplifierMutePin = -1;
+}
+
+// Set the verbosity level
+void setVerboseLevel(int level)
+{
+	gRTAudioVerbose = level;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/Utilities.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,31 @@
+/*
+ * Utilities.cpp
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: parallels
+ */
+
+#include "../include/Utilities.h"
+
+// map()
+//
+// Scale an input value from one range to another. Works like its Wiring language equivalent.
+// x is the value to scale; in_min and in_max are the input range; out_min and out_max
+// are the output range.
+
+float map(float x, float in_min, float in_max, float out_min, float out_max)
+{
+	return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+// constrain()
+//
+// Clips an input value to be between two end points
+// x is the value to constrain; min_val and max_val are the range
+
+float constrain(float x, float min_val, float max_val)
+{
+	if(x < min_val) return min_val;
+	if(x > max_val) return max_val;
+	return x;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/GPIOcontrol.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,77 @@
+/*
+ * SimpleGPIO.h
+ *
+ * Copyright Derek Molloy, School of Electronic Engineering, Dublin City University
+ * www.derekmolloy.ie
+ *
+ * Based on Software by RidgeRun
+ * Copyright (c) 2011, RidgeRun
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the RidgeRun.
+ * 4. Neither the name of the RidgeRun 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 RIDGERUN ''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 RIDGERUN 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 SIMPLEGPIO_H_
+#define SIMPLEGPIO_H_
+
+ /****************************************************************
+ * Constants
+ ****************************************************************/
+
+#define SYSFS_GPIO_DIR "/sys/class/gpio"
+#define SYSFS_LED_DIR  "/sys/class/leds"
+#define POLL_TIMEOUT (3 * 1000) /* 3 seconds */
+#define MAX_BUF 128
+
+enum PIN_DIRECTION{
+	INPUT_PIN=0,
+	OUTPUT_PIN=1
+};
+
+enum PIN_VALUE{
+	LOW=0,
+	HIGH=1
+};
+
+/****************************************************************
+ * gpio_functions
+ ****************************************************************/
+int gpio_setup(unsigned int gpio, int out_flag);
+int gpio_export(unsigned int gpio);
+int gpio_unexport(unsigned int gpio);
+int gpio_set_dir(unsigned int gpio, int out_flag);
+int gpio_set_value(unsigned int gpio, int value);
+int gpio_get_value(unsigned int gpio, unsigned int *value);
+int gpio_set_edge(unsigned int gpio, char *edge);
+int gpio_fd_open(unsigned int gpio, int writeFlag);
+int gpio_fd_close(int fd);
+int gpio_write(int fd, int value);
+int gpio_read(int fd, unsigned int *value);
+int gpio_dismiss(int fd, unsigned int gpio);
+
+int led_set_trigger(unsigned int lednum, const char *trigger);
+
+#endif /* SIMPLEGPIO_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/I2c.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,87 @@
+/*
+ * I2c.h
+ *
+ *  Created on: Oct 14, 2013
+ *      Author: Victor Zappi
+ */
+
+#ifndef I2C_H_
+#define I2C_H_
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <stropts.h>
+
+#define MAX_BUF_NAME 64
+
+using namespace std;
+
+
+class I2c
+{
+
+protected:
+	int i2C_bus;
+	int i2C_address;
+	int i2C_file;
+
+public:
+	int initI2C_RW(int bus, int address, int file);
+	virtual int readI2C() = 0;
+	int closeI2C();
+
+	virtual ~I2c();
+
+};
+
+
+inline int I2c::initI2C_RW(int bus, int address, int fileHnd)
+{
+	i2C_bus 	= bus;
+	i2C_address = address;
+	i2C_file 	= fileHnd;
+
+	// open I2C device as a file
+	char namebuf[MAX_BUF_NAME];
+	snprintf(namebuf, sizeof(namebuf), "/dev/i2c-%d", i2C_bus);
+
+	if ((i2C_file = open(namebuf, O_RDWR)) < 0)
+	{
+			cout << "Failed to open " << namebuf << " I2C Bus" << endl;
+			return(1);
+	}
+
+	// target device as slave
+	if (ioctl(i2C_file, I2C_SLAVE, i2C_address) < 0){
+			cout << "I2C_SLAVE address " << i2C_address << " failed..." << endl;
+			return(2);
+	}
+
+	return 0;
+}
+
+
+
+inline int I2c::closeI2C()
+{
+	if(close(i2C_file)>0)
+	{
+		cout << "Failed to close  file "<< i2C_file << endl;
+		return 1;
+	}
+	return 0;
+}
+
+
+inline I2c::~I2c(){}
+
+
+#endif /* I2C_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/I2c_Codec.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,51 @@
+/*
+ * I2c_Codec.h
+ *
+ * Handle writing the registers to the TLV320AIC310x
+ * series audio codecs, used on the BeagleBone Audio Cape.
+ * This code is designed to bypass the ALSA driver and
+ * configure the codec directly in a sensible way. It
+ * is complemented by code running on the PRU which uses
+ * the McASP serial port to transfer audio data.
+ *
+ *  Created on: May 25, 2014
+ *      Author: Andrew McPherson
+ */
+
+
+#ifndef I2CCODEC_H_
+#define I2CCODEC_H_
+
+#include "I2c.h"
+
+
+class I2c_Codec : public I2c
+{
+public:
+	int writeRegister(unsigned int reg, unsigned int value);
+
+	int initCodec();
+	int startAudio(int dual_rate);
+	int stopAudio();
+
+	int setDACVolume(int halfDbSteps);
+	int writeDACVolumeRegisters(bool mute);
+	int setADCVolume(int halfDbSteps);
+	int writeADCVolumeRegisters(bool mute);
+	int setHPVolume(int halfDbSteps);
+	int writeHPVolumeRegisters();
+
+	int readI2C();
+
+	I2c_Codec();
+	~I2c_Codec();
+
+private:
+	bool running;
+	int dacVolumeHalfDbs;
+	int adcVolumeHalfDbs;
+	int hpVolumeHalfDbs;
+};
+
+
+#endif /* I2CCODEC_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/PRU.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,75 @@
+/*
+ * PRU.h
+ *
+ *  Created on: May 27, 2014
+ *      Author: andrewm
+ */
+
+#ifndef PRU_H_
+#define PRU_H_
+
+#include <stdint.h>
+
+class PRU
+{
+private:
+	static const unsigned int kPruGPIODACSyncPin;
+	static const unsigned int kPruGPIOADCSyncPin;
+	static const unsigned int kPruGPIOTestPin;
+	static const unsigned int kPruGPIOTestPin2;
+	static const unsigned int kPruGPIOTestPin3;
+
+public:
+	// Constructor
+	PRU();
+
+	// Destructor
+	~PRU();
+
+	// Prepare the GPIO pins needed for the PRU
+	int prepareGPIO(int use_spi, int include_test_pin, int include_led);
+
+	// Clean up the GPIO at the end
+	void cleanupGPIO();
+
+	// Initialise and open the PRU
+	int initialise(int pru_num, int frames_per_buffer, bool xenomai_test_pin = false);
+
+	// Run the code image in the specified file
+	int start(char * const filename);
+
+	// Loop: read and write data from the PRU
+	void loop();
+
+	// Wait for an interrupt from the PRU indicate it is finished
+	void waitForFinish();
+
+	// Turn off the PRU when done
+	void disable();
+
+	// For debugging:
+	void setGPIOTestPin();
+	void clearGPIOTestPin();
+
+private:
+	int pru_number;		// Which PRU we use
+	bool running;		// Whether the PRU is running
+	bool spi_enabled;	// Whether SPI ADC and DAC are used
+	bool gpio_enabled;	// Whether GPIO has been prepared
+	bool led_enabled;	// Whether a user LED is enabled
+	bool gpio_test_pin_enabled; // Whether the test pin was also enabled
+
+	volatile uint32_t *pru_buffer_comm;
+	uint16_t *pru_buffer_spi_dac;
+	uint16_t *pru_buffer_spi_adc;
+	int16_t *pru_buffer_audio_dac;
+	int16_t *pru_buffer_audio_adc;
+	unsigned int spi_buffer_frames;
+	unsigned int audio_buffer_frames;
+
+	int xenomai_gpio_fd;	// File descriptor for /dev/mem for fast GPIO
+	uint32_t *xenomai_gpio;	// Pointer to GPIO registers
+};
+
+
+#endif /* PRU_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/RTAudio.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,49 @@
+/*
+ *  RTAudio.h
+ *
+ *  Central control code for hard real-time audio on BeagleBone Black
+ *  using PRU and Xenomai Linux extensions. This code began as part
+ *  of the Hackable Instruments project (EPSRC) at Queen Mary University
+ *  of London, 2013-14.
+ *
+ *  (c) 2014 Victor Zappi and Andrew McPherson
+ *  Queen Mary University of London
+ */
+
+
+#ifndef RTAUDIO_H_
+#define RTAUDIO_H_
+
+#include "render.h"
+
+// Useful constants
+#define DBOX_CAPE					// New custom cape
+
+#ifdef DBOX_CAPE
+#define CODEC_I2C_ADDRESS  0x18		// Address of TLV320AIC3104 codec
+#else
+#define CODEC_I2C_ADDRESS  0x1B		// Address of TLV320AIC3106 codec
+#endif
+
+enum {
+	kAmplifierMutePin = 61	// P8-26 controls amplifier mute
+};
+
+typedef void* AuxiliaryTask;	// Opaque data type to keep track of aux tasks
+
+// Flag that indicates when the audio will stop; can be read or
+// set by other components which should end at the same time as the audio
+extern bool gShouldStop;
+
+int initAudio(int periodSize, int useMatrix, void *userData,
+			  int codecI2CAddress = CODEC_I2C_ADDRESS, int ampMutePin = kAmplifierMutePin);
+int startAudio();
+void stopAudio();
+void cleanupAudio();
+
+AuxiliaryTask createAuxiliaryTaskLoop(void (*functionToCall)(void), int priority, const char *name);
+void scheduleAuxiliaryTask(AuxiliaryTask task);
+
+void setVerboseLevel(int level);
+
+#endif /* RTAUDIO_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/Utilities.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,14 @@
+/*
+ * Utilities.h
+ *
+ *  Created on: Oct 27, 2014
+ *      Author: parallels
+ */
+
+#ifndef UTILITIES_H_
+#define UTILITIES_H_
+
+float map(float x, float in_min, float in_max, float out_min, float out_max);
+float constrain(float x, float min_val, float max_val);
+
+#endif /* UTILITIES_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/pruss_intc_mapping.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,104 @@
+/*
+ * pruss_intc_mapping.h
+ * 
+ * Example PRUSS INTC mapping for the application
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 
+ * 
+ * 
+ *  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 Texas Instruments Incorporated 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.
+ *
+*/
+
+/*
+ * ============================================================================
+ * Copyright (c) Texas Instruments Inc 2010-11
+ *
+ * Use of this software is controlled by the terms and conditions found in the
+ * license agreement under which this software has been supplied or provided.
+ * ============================================================================
+*/
+
+#define AM33XX
+#ifdef AM33XX
+#define PRU0_PRU1_INTERRUPT     17
+#define PRU1_PRU0_INTERRUPT     18
+#define PRU0_ARM_INTERRUPT      19
+#define PRU1_ARM_INTERRUPT      20
+#define ARM_PRU0_INTERRUPT      21
+#define ARM_PRU1_INTERRUPT      22
+#else
+#define PRU0_PRU1_INTERRUPT     32
+#define PRU1_PRU0_INTERRUPT     33
+#define PRU0_ARM_INTERRUPT      34
+#define PRU1_ARM_INTERRUPT      35
+#define ARM_PRU0_INTERRUPT      36
+#define ARM_PRU1_INTERRUPT      37
+#endif
+#define CHANNEL0                0
+#define CHANNEL1                1
+#define CHANNEL2                2
+#define CHANNEL3                3
+#define CHANNEL4                4
+#define CHANNEL5                5
+#define CHANNEL6                6
+#define CHANNEL7                7
+#define CHANNEL8                8
+#define CHANNEL9                9
+
+#define PRU0                    0
+#define PRU1                    1
+#define PRU_EVTOUT0             2
+#define PRU_EVTOUT1             3
+#define PRU_EVTOUT2             4
+#define PRU_EVTOUT3             5
+#define PRU_EVTOUT4             6
+#define PRU_EVTOUT5             7
+#define PRU_EVTOUT6             8
+#define PRU_EVTOUT7             9
+
+#define PRU0_HOSTEN_MASK            0x0001
+#define PRU1_HOSTEN_MASK            0x0002
+#define PRU_EVTOUT0_HOSTEN_MASK     0x0004
+#define PRU_EVTOUT1_HOSTEN_MASK     0x0008
+#define PRU_EVTOUT2_HOSTEN_MASK     0x0010
+#define PRU_EVTOUT3_HOSTEN_MASK     0x0020
+#define PRU_EVTOUT4_HOSTEN_MASK     0x0040
+#define PRU_EVTOUT5_HOSTEN_MASK     0x0080
+#define PRU_EVTOUT6_HOSTEN_MASK     0x0100
+#define PRU_EVTOUT7_HOSTEN_MASK     0x0200
+
+
+#define PRUSS_INTC_INITDATA {   \
+{ PRU0_PRU1_INTERRUPT, PRU1_PRU0_INTERRUPT, PRU0_ARM_INTERRUPT, PRU1_ARM_INTERRUPT, ARM_PRU0_INTERRUPT, ARM_PRU1_INTERRUPT,  -1  },  \
+{ {PRU0_PRU1_INTERRUPT,CHANNEL1}, {PRU1_PRU0_INTERRUPT, CHANNEL0}, {PRU0_ARM_INTERRUPT,CHANNEL2}, {PRU1_ARM_INTERRUPT, CHANNEL3}, {ARM_PRU0_INTERRUPT, CHANNEL0}, {ARM_PRU1_INTERRUPT, CHANNEL1},  {-1,-1}},  \
+ {  {CHANNEL0,PRU0}, {CHANNEL1, PRU1}, {CHANNEL2, PRU_EVTOUT0}, {CHANNEL3, PRU_EVTOUT1}, {-1,-1} },  \
+ (PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK | PRU_EVTOUT1_HOSTEN_MASK) /*Enable PRU0, PRU1, PRU_EVTOUT0 */ \
+} \
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/prussdrv.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,160 @@
+/*
+ * prussdrv.h
+ * 
+ * Describes PRUSS userspace driver for Industrial Communications
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 
+ * 
+ * 
+ *  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 Texas Instruments Incorporated 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.
+ *
+*/
+
+/*
+ * ============================================================================
+ * Copyright (c) Texas Instruments Inc 2010-11
+ *
+ * Use of this software is controlled by the terms and conditions found in the
+ * license agreement under which this software has been supplied or provided.
+ * ============================================================================
+*/
+
+#ifndef _PRUSSDRV_H
+#define _PRUSSDRV_H
+
+#include <sys/types.h>
+#include <pthread.h>
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#define NUM_PRU_HOSTIRQS        8
+#define NUM_PRU_HOSTS          10
+#define NUM_PRU_CHANNELS       10
+#define NUM_PRU_SYS_EVTS       64
+
+#define PRUSS0_PRU0_DATARAM     0
+#define PRUSS0_PRU1_DATARAM     1
+#define PRUSS0_PRU0_IRAM        2
+#define PRUSS0_PRU1_IRAM        3
+
+//Available in AM33xx series - begin
+#define PRUSS0_SHARED_DATARAM   4
+#define	PRUSS0_CFG              5
+#define	PRUSS0_UART             6
+#define	PRUSS0_IEP              7
+#define	PRUSS0_ECAP             8
+#define	PRUSS0_MII_RT           9
+#define	PRUSS0_MDIO            10
+//Available in AM33xx series - end
+
+#define PRU_EVTOUT_0            0
+#define PRU_EVTOUT_1            1
+#define PRU_EVTOUT_2            2
+#define PRU_EVTOUT_3            3
+#define PRU_EVTOUT_4            4
+#define PRU_EVTOUT_5            5
+#define PRU_EVTOUT_6            6
+#define PRU_EVTOUT_7            7
+
+    typedef void *(*prussdrv_function_handler) (void *);
+    typedef struct __sysevt_to_channel_map {
+        short sysevt;
+        short channel;
+    } tsysevt_to_channel_map;
+    typedef struct __channel_to_host_map {
+        short channel;
+        short host;
+    } tchannel_to_host_map;
+    typedef struct __pruss_intc_initdata {
+        //Enabled SYSEVTs - Range:0..63
+        //{-1} indicates end of list
+        char sysevts_enabled[NUM_PRU_SYS_EVTS];
+        //SysEvt to Channel map. SYSEVTs - Range:0..63 Channels -Range: 0..9
+        //{-1, -1} indicates end of list
+        tsysevt_to_channel_map sysevt_to_channel_map[NUM_PRU_SYS_EVTS];
+        //Channel to Host map.Channels -Range: 0..9  HOSTs - Range:0..9
+        //{-1, -1} indicates end of list
+        tchannel_to_host_map channel_to_host_map[NUM_PRU_CHANNELS];
+        //10-bit mask - Enable Host0-Host9 {Host0/1:PRU0/1, Host2..9 : PRUEVT_OUT0..7)
+        unsigned int host_enable_bitmask;
+    } tpruss_intc_initdata;
+
+    int prussdrv_init(void);
+
+    int prussdrv_open(unsigned int pru_evtout_num);
+
+    int prussdrv_pru_reset(unsigned int prunum);
+
+    int prussdrv_pru_disable(unsigned int prunum);
+
+    int prussdrv_pru_enable(unsigned int prunum);
+
+    int prussdrv_pru_write_memory(unsigned int pru_ram_id,
+                                  unsigned int wordoffset,
+                                  unsigned int *memarea,
+                                  unsigned int bytelength);
+
+    int prussdrv_pruintc_init(tpruss_intc_initdata * prussintc_init_data);
+
+    int prussdrv_map_l3mem(void **address);
+
+    int prussdrv_map_extmem(void **address);
+
+    int prussdrv_map_prumem(unsigned int pru_ram_id, void **address);
+
+    int prussdrv_map_peripheral_io(unsigned int per_id, void **address);
+
+    unsigned int prussdrv_get_phys_addr(void *address);
+
+    void *prussdrv_get_virt_addr(unsigned int phyaddr);
+
+    int prussdrv_pru_wait_event(unsigned int pru_evtout_num);
+
+    int prussdrv_pru_send_event(unsigned int eventnum);
+
+    int prussdrv_pru_clear_event(unsigned int eventnum);
+
+    int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum,
+                                           unsigned int pru_evtout_num,
+                                           unsigned int ack_eventnum);
+
+    int prussdrv_exit(void);
+
+    int prussdrv_exec_program(int prunum, char *filename);
+
+    int prussdrv_start_irqthread(unsigned int pru_evtout_num, int priority,
+                                 prussdrv_function_handler irqhandler);
+
+
+#if defined (__cplusplus)
+}
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/render.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,53 @@
+/*
+ * render.h
+ *
+ *  Created on: May 28, 2014
+ *      Author: Victor Zappi
+ */
+
+#ifndef RENDER_H_
+#define RENDER_H_
+
+// uint types
+#include <stdint.h>
+
+// Mappings from pin numbers on PCB to actual DAC channels
+// This gives the DAC and ADC connectors the same effective pinout
+#define DAC_PIN0	6
+#define DAC_PIN1	4
+#define DAC_PIN2	2
+#define DAC_PIN3	0
+#define DAC_PIN4	1
+#define DAC_PIN5	3
+#define DAC_PIN6	5
+#define DAC_PIN7	7
+
+#define ADC_PIN0	0
+#define ADC_PIN1	1
+#define ADC_PIN2	2
+#define ADC_PIN3	3
+#define ADC_PIN4	4
+#define ADC_PIN5	5
+#define ADC_PIN6	6
+#define ADC_PIN7	7
+
+#define MATRIX_MAX  65535.0
+
+bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
+					   int numAudioFramesPerPeriod,
+					   float matrixSampleRate, float audioSampleRate,
+					   void *userData);
+
+void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut);
+
+void render_medium_prio();
+void render_low_prio();
+
+void schedule_render_medium_prio();
+void schedule_render_low_prio();
+
+
+void cleanup_render();
+
+#endif /* RENDER_H_ */
Binary file libNE10.a has changed
Binary file libprussdrv.a has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic/main.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,114 @@
+/*
+ * main.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <libgen.h>
+#include <signal.h>
+#include "../../include/RTAudio.h"
+
+using namespace std;
+
+// Handle Ctrl-C by requesting that the audio rendering stop
+void interrupt_handler(int var)
+{
+	gShouldStop = true;
+}
+
+// Print usage information
+void usage(const char * processName)
+{
+	cerr << "Usage: " << processName << " [-h] [-v] [-p period] [-f frequency]" << endl;
+	cerr << "   -h:           Print this menu\n";
+	cerr << "   -v:           Enable verbose messages\n";
+	cerr << "   -p period:    Set the period (hardware buffer) size in sensor frames\n";
+	cerr << "   -f frequency: Set the frequency of the oscillator\n";
+	cerr << "   -m:           Enable the matrix (ADC and DAC) as well as audio\n";
+}
+
+int main(int argc, char *argv[])
+{
+	int periodSize = 8;			// Period size in sensor frames
+	int verbose = 0;			// Verbose printing level
+	float frequency = 440.0;	// Frequency of oscillator
+	int useMatrix = 0;			// Whether to use the matrix or just audio
+
+	// Parse command-line arguments
+	while (1) {
+		int c;
+		if ((c = getopt(argc, argv, "hp:vf:m")) < 0)
+				break;
+		switch (c) {
+		case 'h':
+				usage(basename(argv[0]));
+				exit(0);
+		case 'p':
+				periodSize = atoi(optarg);
+				if(periodSize < 1)
+					periodSize = 1;
+				break;
+		case 'v':
+				verbose = 1;
+				break;
+		case 'f':
+				frequency = atof(optarg);
+				break;
+		case 'm':
+				useMatrix = 1;
+				break;
+		case '?':
+		default:
+				usage(basename(argv[0]));
+				exit(1);
+		}
+	}
+
+
+	// Set verbose logging information (optional by using value > 0; default is 0)
+	setVerboseLevel(verbose);
+
+	if(verbose) {
+		cout << "Starting with period size " << periodSize << " and frequency " << frequency << endl;
+		if(useMatrix)
+			cout << "Matrix enabled\n";
+		else
+			cout << "Matrix disabled\n";
+	}
+
+	// Initialise the PRU audio device
+	if(initAudio(periodSize, useMatrix, &frequency) != 0) {
+		cout << "Error: unable to initialise audio" << endl;
+		return -1;
+	}
+
+	// Start the audio device running
+	if(startAudio()) {
+		cout << "Error: unable to start real-time audio" << endl;
+		return -1;
+	}
+
+	// Set up interrupt handler to catch Control-C
+	signal(SIGINT, interrupt_handler);
+
+	// Run until told to stop
+	while(!gShouldStop) {
+		usleep(100000);
+	}
+
+	// Stop the audio device
+	stopAudio();
+
+	if(verbose) {
+		cout << "Cleaning up..." << endl;
+	}
+
+	// Clean up any resources allocated for audio
+	cleanupAudio();
+
+	// All done!
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic/render.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,65 @@
+/*
+ * render.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+
+#include "../../include/render.h"
+#include <cmath>
+
+float gFrequency;
+float gPhase;
+float gInverseSampleRate;
+int gNumChannels;
+
+// initialise_render() is called once before the audio rendering starts.
+// Use it to perform any initialisation and allocation which is dependent
+// on the period size or sample rate.
+//
+// userData holds an opaque pointer to a data structure that was passed
+// in from the call to initAudio().
+//
+// Return true on success; returning false halts the program.
+
+bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
+					   int numAudioFramesPerPeriod, float matrixSampleRate,
+					   float audioSampleRate, void *userData)
+{
+	// Retrieve a parameter passed in from the initAudio() call
+	gFrequency = *(float *)userData;
+
+	gNumChannels = numChannels;
+	gInverseSampleRate = 1.0 / audioSampleRate;
+	gPhase = 0.0;
+
+	return true;
+}
+
+// render() is called regularly at the highest priority by the audio engine.
+// Input and output are given from the audio hardware and the other
+// ADCs and DACs (if available). If only audio is available, numMatrixFrames
+// will be 0.
+
+void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut)
+{
+	for(int n = 0; n < numAudioFrames; n++) {
+		float out = 0.8f * sinf(gPhase);
+		gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate;
+		if(gPhase > 2.0 * M_PI)
+			gPhase -= 2.0 * M_PI;
+
+		for(int channel = 0; channel < gNumChannels; channel++)
+			audioOut[n * gNumChannels + channel] = out;
+	}
+}
+
+// cleanup_render() is called once at the end, after the audio has stopped.
+// Release any resources that were allocated in initialise_render().
+
+void cleanup_render()
+{
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic_analog_output/main.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,109 @@
+/*
+ * main.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <libgen.h>
+#include <signal.h>
+#include "../../include/RTAudio.h"
+
+using namespace std;
+
+// Handle Ctrl-C by requesting that the audio rendering stop
+void interrupt_handler(int var)
+{
+	gShouldStop = true;
+}
+
+// Print usage information
+void usage(const char * processName)
+{
+	cerr << "Usage: " << processName << " [-h] [-v] [-p period] [-f input] [-a input]" << endl;
+	cerr << "   -h:           Print this menu\n";
+	cerr << "   -v:           Enable verbose messages\n";
+	cerr << "   -p period:    Set the period (hardware buffer) size in sensor frames\n";
+	cerr << "   -f frequency: Set frequency of LED fade (default: 1.0)\n";
+}
+
+int main(int argc, char *argv[])
+{
+	int periodSize = 8;			// Period size in sensor frames
+	int verbose = 0;			// Verbose printing level
+	float frequency = 1.0;		// Frequency of LED fades
+
+	// Parse command-line arguments
+	while (1) {
+		int c;
+		if ((c = getopt(argc, argv, "hp:vf:")) < 0)
+				break;
+		switch (c) {
+		case 'h':
+				usage(basename(argv[0]));
+				exit(0);
+		case 'p':
+				periodSize = atoi(optarg);
+				if(periodSize < 1)
+					periodSize = 1;
+				break;
+		case 'v':
+				verbose = 1;
+				break;
+		case 'f':
+				frequency = atof(optarg);
+				if(frequency < 0)
+					frequency = 0;
+				if(frequency > 11025.0)
+					frequency = 11025.0;
+				break;
+		case '?':
+		default:
+				usage(basename(argv[0]));
+				exit(1);
+		}
+	}
+
+
+	// Set verbose logging information (optional by using value > 0; default is 0)
+	setVerboseLevel(verbose);
+
+	if(verbose) {
+		cout << "Starting with period size " << periodSize << " and frequency " << frequency <<  endl;
+	}
+
+	// Initialise the PRU audio device
+	if(initAudio(periodSize, 1, &frequency) != 0) {
+		cout << "Error: unable to initialise audio" << endl;
+		return -1;
+	}
+
+	// Start the audio device running
+	if(startAudio()) {
+		cout << "Error: unable to start real-time audio" << endl;
+		return -1;
+	}
+
+	// Set up interrupt handler to catch Control-C
+	signal(SIGINT, interrupt_handler);
+
+	// Run until told to stop
+	while(!gShouldStop) {
+		usleep(100000);
+	}
+
+	// Stop the audio device
+	stopAudio();
+
+	if(verbose) {
+		cout << "Cleaning up..." << endl;
+	}
+
+	// Clean up any resources allocated for audio
+	cleanupAudio();
+
+	// All done!
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic_analog_output/render.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,83 @@
+/*
+ * render.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+
+#include "../../include/render.h"
+#include "../../include/Utilities.h"
+#include <rtdk.h>
+#include <cmath>
+
+// Set range for analog outputs designed for driving LEDs
+const float kMinimumAmplitude = (1.5 / 5.0) * MATRIX_MAX;
+const float kAmplitudeRange = MATRIX_MAX - kMinimumAmplitude;
+
+float gFrequency;
+float gPhase;
+float gInverseSampleRate;
+
+// initialise_render() is called once before the audio rendering starts.
+// Use it to perform any initialisation and allocation which is dependent
+// on the period size or sample rate.
+//
+// userData holds an opaque pointer to a data structure that was passed
+// in from the call to initAudio().
+//
+// Return true on success; returning false halts the program.
+
+bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
+					   int numAudioFramesPerPeriod, float matrixSampleRate,
+					   float audioSampleRate, void *userData)
+{
+	// Retrieve a parameter passed in from the initAudio() call
+	gFrequency = *(float *)userData;
+
+	if(numMatrixFramesPerPeriod*2 != numAudioFramesPerPeriod) {
+		rt_printf("Error: this example needs the matrix enabled, running at half audio rate\n");
+		return false;
+	}
+
+	gInverseSampleRate = 1.0 / audioSampleRate;
+	gPhase = 0.0;
+
+	return true;
+}
+
+// render() is called regularly at the highest priority by the audio engine.
+// Input and output are given from the audio hardware and the other
+// ADCs and DACs (if available). If only audio is available, numMatrixFrames
+// will be 0.
+
+void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut)
+{
+	for(int n = 0; n < numMatrixFrames; n++) {
+		// Set LED to different phase for each matrix channel
+		float relativePhase = 0.0;
+		for(int channel = 0; channel < 8; channel++) {
+			float out = kMinimumAmplitude + kAmplitudeRange * 0.5f * (1.0f + sinf(gPhase + relativePhase));
+			if(out > MATRIX_MAX)
+				out = MATRIX_MAX;
+
+			matrixOut[n * 8 + channel] = (uint16_t)out;
+
+			// Advance by pi/4 (1/8 of a full rotation) for each channel
+			relativePhase += M_PI * 0.25;
+		}
+
+		gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate;
+		if(gPhase > 2.0 * M_PI)
+			gPhase -= 2.0 * M_PI;
+	}
+}
+
+// cleanup_render() is called once at the end, after the audio has stopped.
+// Release any resources that were allocated in initialise_render().
+
+void cleanup_render()
+{
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic_sensor/main.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,121 @@
+/*
+ * main.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <libgen.h>
+#include <signal.h>
+#include "../../include/RTAudio.h"
+
+using namespace std;
+
+int gSensorInputFrequency = 0;
+int gSensorInputAmplitude = 1;
+
+// Handle Ctrl-C by requesting that the audio rendering stop
+void interrupt_handler(int var)
+{
+	gShouldStop = true;
+}
+
+// Print usage information
+void usage(const char * processName)
+{
+	cerr << "Usage: " << processName << " [-h] [-v] [-p period] [-f input] [-a input]" << endl;
+	cerr << "   -h:           Print this menu\n";
+	cerr << "   -v:           Enable verbose messages\n";
+	cerr << "   -p period:    Set the period (hardware buffer) size in sensor frames\n";
+	cerr << "   -f input:     Choose the analog input controlling frequency (0-7; default 0)\n";
+	cerr << "   -a input:     Choose the analog input controlling amplitude (0-7; default 1)\n";
+}
+
+int main(int argc, char *argv[])
+{
+	int periodSize = 8;			// Period size in sensor frames
+	int verbose = 0;			// Verbose printing level
+
+	// Parse command-line arguments
+	while (1) {
+		int c;
+		if ((c = getopt(argc, argv, "hp:vf:a:")) < 0)
+				break;
+		switch (c) {
+		case 'h':
+				usage(basename(argv[0]));
+				exit(0);
+		case 'p':
+				periodSize = atoi(optarg);
+				if(periodSize < 1)
+					periodSize = 1;
+				break;
+		case 'v':
+				verbose = 1;
+				break;
+		case 'f':
+				gSensorInputFrequency = atoi(optarg);
+				if(gSensorInputFrequency < 0 || gSensorInputFrequency > 7) {
+					usage(basename(argv[0]));
+					exit(0);
+				}
+				break;
+		case 'a':
+				gSensorInputAmplitude = atoi(optarg);
+				if(gSensorInputAmplitude < 0 || gSensorInputAmplitude > 7) {
+					usage(basename(argv[0]));
+					exit(0);
+				}
+				break;
+		case '?':
+		default:
+				usage(basename(argv[0]));
+				exit(1);
+		}
+	}
+
+
+	// Set verbose logging information (optional by using value > 0; default is 0)
+	setVerboseLevel(verbose);
+
+	if(verbose) {
+		cout << "Starting with period size " << periodSize << endl;
+		cout << "--> Frequency on input " << gSensorInputFrequency << endl;
+		cout << "--> Amplitude on input " << gSensorInputAmplitude << endl;
+	}
+
+	// Initialise the PRU audio device
+	if(initAudio(periodSize, 1, 0) != 0) {
+		cout << "Error: unable to initialise audio" << endl;
+		return -1;
+	}
+
+	// Start the audio device running
+	if(startAudio()) {
+		cout << "Error: unable to start real-time audio" << endl;
+		return -1;
+	}
+
+	// Set up interrupt handler to catch Control-C
+	signal(SIGINT, interrupt_handler);
+
+	// Run until told to stop
+	while(!gShouldStop) {
+		usleep(100000);
+	}
+
+	// Stop the audio device
+	stopAudio();
+
+	if(verbose) {
+		cout << "Cleaning up..." << endl;
+	}
+
+	// Clean up any resources allocated for audio
+	cleanupAudio();
+
+	// All done!
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic_sensor/render.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,88 @@
+/*
+ * render.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+
+#include "../../include/render.h"
+#include "../../include/Utilities.h"
+#include <rtdk.h>
+#include <cmath>
+
+float gPhase;
+float gInverseSampleRate;
+int gNumChannels;
+
+// These settings are carried over from main.cpp
+// Setting global variables is an alternative approach
+// to passing a structure to userData in initialise_render()
+
+extern int gSensorInputFrequency;
+extern int gSensorInputAmplitude;
+
+// initialise_render() is called once before the audio rendering starts.
+// Use it to perform any initialisation and allocation which is dependent
+// on the period size or sample rate.
+//
+// userData holds an opaque pointer to a data structure that was passed
+// in from the call to initAudio().
+//
+// Return true on success; returning false halts the program.
+
+bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
+					   int numAudioFramesPerPeriod, float matrixSampleRate,
+					   float audioSampleRate, void *userData)
+{
+	if(numMatrixFramesPerPeriod*2 != numAudioFramesPerPeriod) {
+		rt_printf("Error: this example needs the matrix enabled, running at half audio rate\n");
+		return false;
+	}
+
+	gNumChannels = numChannels;
+	gInverseSampleRate = 1.0 / audioSampleRate;
+	gPhase = 0.0;
+
+	return true;
+}
+
+// render() is called regularly at the highest priority by the audio engine.
+// Input and output are given from the audio hardware and the other
+// ADCs and DACs (if available). If only audio is available, numMatrixFrames
+// will be 0.
+
+void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut)
+{
+	float frequency = 0;
+	float amplitude = 0;
+
+	// There are twice as many audio frames as matrix frames since audio sample rate
+	// is twice as high
+
+	for(int n = 0; n < numAudioFrames; n++) {
+		if(!(n % 2)) {
+			// Even audio samples: update frequency and amplitude from the matrix
+			frequency = map((float)matrixIn[gSensorInputFrequency], 0, MATRIX_MAX, 100, 1000);
+			amplitude = (float)matrixIn[gSensorInputAmplitude] / MATRIX_MAX;
+		}
+
+		float out = amplitude * sinf(gPhase);
+
+		for(int channel = 0; channel < gNumChannels; channel++)
+			audioOut[n * gNumChannels + channel] = out;
+
+		gPhase += 2.0 * M_PI * frequency * gInverseSampleRate;
+		if(gPhase > 2.0 * M_PI)
+			gPhase -= 2.0 * M_PI;
+	}
+}
+
+// cleanup_render() is called once at the end, after the audio has stopped.
+// Release any resources that were allocated in initialise_render().
+
+void cleanup_render()
+{
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/ADSR.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,76 @@
+//
+//  ADSR.cpp
+//
+//  Created by Nigel Redmon on 12/18/12.
+//  EarLevel Engineering: earlevel.com
+//  Copyright 2012 Nigel Redmon
+//
+//  For a complete explanation of the ADSR envelope generator and code,
+//  read the series of articles by the author, starting here:
+//  http://www.earlevel.com/main/2013/06/01/envelope-generators/
+//
+//  License:
+//
+//  This source code is provided as is, without warranty.
+//  You may copy and distribute verbatim copies of this document.
+//  You may modify and use this source code to create binary code for your own purposes, free or commercial.
+//
+
+#include "ADSR.h"
+#include <math.h>
+
+
+ADSR::ADSR(void) {
+    reset();
+    setAttackRate(0);
+    setDecayRate(0);
+    setReleaseRate(0);
+    setSustainLevel(1.0);
+    setTargetRatioA(0.3);
+    setTargetRatioDR(0.0001);
+}
+
+ADSR::~ADSR(void) {
+}
+
+void ADSR::setAttackRate(float rate) {
+    attackRate = rate;
+    attackCoef = calcCoef(rate, targetRatioA);
+    attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef);
+}
+
+void ADSR::setDecayRate(float rate) {
+    decayRate = rate;
+    decayCoef = calcCoef(rate, targetRatioDR);
+    decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
+}
+
+void ADSR::setReleaseRate(float rate) {
+    releaseRate = rate;
+    releaseCoef = calcCoef(rate, targetRatioDR);
+    releaseBase = -targetRatioDR * (1.0 - releaseCoef);
+}
+
+float ADSR::calcCoef(float rate, float targetRatio) {
+    return exp(-log((1.0 + targetRatio) / targetRatio) / rate);
+}
+
+void ADSR::setSustainLevel(float level) {
+    sustainLevel = level;
+    decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
+}
+
+void ADSR::setTargetRatioA(float targetRatio) {
+    if (targetRatio < 0.000000001)
+        targetRatio = 0.000000001;  // -180 dB
+    targetRatioA = targetRatio;
+    attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef);
+}
+
+void ADSR::setTargetRatioDR(float targetRatio) {
+    if (targetRatio < 0.000000001)
+        targetRatio = 0.000000001;  // -180 dB
+    targetRatioDR = targetRatio;
+    decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
+    releaseBase = -targetRatioDR * (1.0 - releaseCoef);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/ADSR.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,137 @@
+//
+//  ADRS.h
+//
+//  Created by Nigel Redmon on 12/18/12.
+//  EarLevel Engineering: earlevel.com
+//  Copyright 2012 Nigel Redmon
+//
+//  For a complete explanation of the ADSR envelope generator and code,
+//  read the series of articles by the author, starting here:
+//  http://www.earlevel.com/main/2013/06/01/envelope-generators/
+//
+//  License:
+//
+//  This source code is provided as is, without warranty.
+//  You may copy and distribute verbatim copies of this document.
+//  You may modify and use this source code to create binary code for your own purposes, free or commercial.
+//
+
+#ifndef ADRS_h
+#define ADRS_h
+
+#include <stdio.h>
+#include <string>
+
+using namespace std;
+
+enum envState {
+	env_idle = 0,
+	env_attack,
+	env_decay,
+	env_sustain,
+	env_release
+};
+
+class ADSR {
+public:
+	ADSR(void);
+	~ADSR(void);
+	float process(void);
+	float process(int sampleCount);
+    float getOutput(void);
+    int getState(void);
+	void gate(int on);
+    void setAttackRate(float rate);
+    void setDecayRate(float rate);
+    void setReleaseRate(float rate);
+	void setSustainLevel(float level);
+    void setTargetRatioA(float targetRatio);
+    void setTargetRatioDR(float targetRatio);
+    void reset(void);
+
+protected:
+	int state;
+	float output;
+	float attackRate;
+	float decayRate;
+	float releaseRate;
+	float attackCoef;
+	float decayCoef;
+	float releaseCoef;
+	float sustainLevel;
+    float targetRatioA;
+    float targetRatioDR;
+    float attackBase;
+    float decayBase;
+    float releaseBase;
+	string name;
+    float calcCoef(float rate, float targetRatio);
+};
+
+inline float ADSR::process() {
+	switch (state) {
+        case env_idle:
+            break;
+        case env_attack:
+            output = attackBase + output * attackCoef;
+            if (output >= 1.0) {
+                output = 1.0;
+                state = env_decay;
+            }
+            break;
+        case env_decay:
+            output = decayBase + output * decayCoef;
+            if (output <= sustainLevel) {
+                output = sustainLevel;
+                state = env_sustain;
+            }
+            break;
+        case env_sustain:
+            break;
+        case env_release:
+            output = releaseBase + output * releaseCoef;
+            if (output <= 0.0) {
+                output = 0.0;
+                state = env_idle;
+            }
+            break;
+	}
+	return output;
+}
+
+inline float ADSR::process(int sampleCount)
+{
+	float retVal = 0;
+
+	if(state != env_idle)
+	{
+		for(int i=0; i<sampleCount; i++)
+			retVal = process();
+	}
+
+	return retVal;
+}
+
+inline void ADSR::gate(int gate) {
+
+	if (gate)
+		state = env_attack;
+	else if (state != env_idle)
+        state = env_release;
+}
+
+inline int ADSR::getState() {
+    return state;
+}
+
+inline void ADSR::reset() {
+    state = env_idle;
+    output = 0.0;
+}
+
+inline float ADSR::getOutput() {
+	return output;
+}
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/AnalogInput.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,163 @@
+/*
+ * AnalogInput.cpp
+ *
+ *  Created on: Oct 17, 2013
+ *      Author: Victor Zappi
+ */
+
+
+#include "AnalogInput.h"
+
+using namespace std;
+
+
+AnalogInput::AnalogInput()
+{
+	ActivateAnalogHnd  = NULL;
+	activateAnalogPath = "";
+	analogIsSet        = false;
+
+	AnalogInHnd    = NULL;
+	analogInPath   = "";
+	helperNumFound = false;
+
+	// support var for init
+	// these are fixed for BBB
+	startPath = "/sys/devices/bone_capemgr.*/slots";
+	readPath = "";
+
+	buffer = (char*) malloc (sizeof(char)*lSize); // reading buffer
+
+	verbose = false;
+}
+
+
+AnalogInput::~AnalogInput()
+{
+	free(buffer);
+}
+
+int AnalogInput::initAnalogInputs()
+{
+	 if(analogIsSet)
+	 {
+		 if(verbose)
+			 cout << "Fine, but Analog Input already active..."<< endl;
+		 return 0;
+	 }
+
+	// title
+	 if(verbose)
+	 	cout << "Init Analog Input"<< endl;
+
+
+	  // first: activate analog pins on cape manager
+	  // cape-bone-iio > /sys/devices/bone_capemgr.*/slots
+
+	  // we have to look for the semi-random number the BBB has initialized the bone_capemgr with [value of *]
+	  // to reach /slots and set cape-bone-iio.
+	  // to do so, we use glob lib, which translates wildcards [*] into all the values found in paths
+
+
+	  glob( startPath.c_str(), 0, NULL, &globbuf);
+
+	  if(globbuf.gl_pathc >0)
+	  {
+	    if (globbuf.gl_pathc == 1 )
+	    {
+	      activateAnalogPath = globbuf.gl_pathv[0];
+
+	      // check if file is existing
+	      if((ActivateAnalogHnd = fopen(activateAnalogPath.c_str(), "r+")) != NULL)
+	      {
+	        // we found that current capemgr num
+
+			fwrite("cape-bone-iio", sizeof(char), 13, ActivateAnalogHnd); // activate pins
+
+	        analogIsSet = true;
+
+			if(verbose)
+				cout << "Analog Pins activated via cape-bone-iio at path " << activateAnalogPath << endl;
+
+			fclose(ActivateAnalogHnd); // close file
+	      }
+	    }
+	    //else
+	      //printf("toomany", );
+	  }
+
+	  globfree(&globbuf); // self freeing
+
+
+	  if(!analogIsSet)
+	  {
+	    cout << "cannot find bone_capemgr" << endl;
+	    cout << "------Init failed------" << endl;
+	    return 1;
+	  }
+
+
+	  // build read path
+	  startPath = "/sys/devices/ocp.2/helper.*";
+
+	  glob( startPath.c_str(), 0, NULL, &globbuf);
+
+	  if(globbuf.gl_pathc >0)
+	  {
+		if (globbuf.gl_pathc == 1 )
+		{
+		  analogInPath = globbuf.gl_pathv[0] + (string)"/AIN";
+		}
+	    else
+	      cout << "Too many analog inputs with this name! [I am puzzled...]" << endl;
+	  }
+	  else
+	    cout << "Cannot find analog input dir...puzzled" << endl;
+
+
+	  return 0;
+}
+
+
+int AnalogInput::read(int index)
+{
+	  // convert int index into string
+	  stringstream ss;
+	  ss << index;
+
+	  readPath = analogInPath + ss.str(); // create pin0 file path
+
+
+	  // check if file is existing
+	  if((AnalogInHnd = fopen(readPath.c_str(), "rb")) != NULL)
+	  {
+		// we found that current helper num
+
+		// prepare read buffer to reading
+		fseek (AnalogInHnd , 0 , SEEK_END);
+		lSize = ftell (AnalogInHnd);
+		rewind (AnalogInHnd);
+
+		result = fread (buffer, 1, lSize, AnalogInHnd);
+
+		fclose(AnalogInHnd); // close file
+
+		helperNumFound = true;
+
+		//cout << "Analog Pins can be read at path " << analogInPath << endl;
+		//cout << "Test reading of Pin0 gives: " << buffer << endl;
+	  }
+
+	  if(!helperNumFound)
+	  {
+	    cout << "cannot find helper" << endl;
+	    cout << "------Analog Read failed------" << endl;
+	    return -1;
+	  }
+
+	  return atoi(buffer);
+
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/AnalogInput.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,55 @@
+/*
+ * AnalogInput.h
+ *
+ *  Created on: Oct 17, 2013
+ *      Author: Victor Zappi
+ */
+
+#ifndef ANALOGINPUT_H_
+#define ANALOGINPUT_H_
+
+#include <iostream>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glob.h>
+
+using namespace std;
+
+class AnalogInput
+{
+private:
+	FILE *ActivateAnalogHnd;
+	string activateAnalogPath;
+	bool analogIsSet;
+
+	FILE *AnalogInHnd;
+	string analogInPath;
+	bool helperNumFound;
+
+	// suport var for init
+	string startPath;
+	string readPath;
+
+	glob_t  globbuf;
+
+	// support vars for pin reading
+	long lSize;
+	char * buffer;
+	size_t result;
+
+	bool verbose;
+
+public:
+	AnalogInput();
+	~AnalogInput();
+
+	int initAnalogInputs();
+	int read(int index);
+
+};
+
+
+
+
+#endif /* ANALOGINPUT_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/Biquad.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,169 @@
+//
+//  Biquad.cpp
+//
+//  Created by Nigel Redmon on 11/24/12
+//  EarLevel Engineering: earlevel.com
+//  Copyright 2012 Nigel Redmon
+//
+//  For a complete explanation of the Biquad code:
+//  http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/
+//
+//  License:
+//
+//  This source code is provided as is, without warranty.
+//  You may copy and distribute verbatim copies of this document.
+//  You may modify and use this source code to create binary code
+//  for your own purposes, free or commercial.
+//
+
+#include <math.h>
+#include "Biquad.h"
+#include <iostream>
+
+Biquad::Biquad() {
+    type = bq_type_lowpass;
+    a0 = 1.0;
+    a1 = a2 = b1 = b2 = 0.0;
+    Fc = 0.50;
+    Q = 0.707;
+    peakGain = 0.0;
+    z1 = z2 = 0.0;
+}
+
+Biquad::Biquad(int type, double Fc, double Q, double peakGainDB) {
+    setBiquad(type, Fc, Q, peakGainDB);
+    z1 = z2 = 0.0;
+}
+
+Biquad::~Biquad() {
+}
+
+void Biquad::setType(int type) {
+    this->type = type;
+    calcBiquad();
+}
+
+void Biquad::setQ(double Q) {
+    this->Q = Q;
+    calcBiquad();
+}
+
+void Biquad::setFc(double Fc) {
+    this->Fc = Fc;
+    calcBiquad();
+}
+
+void Biquad::setPeakGain(double peakGainDB) {
+    this->peakGain = peakGainDB;
+    calcBiquad();
+}
+    
+void Biquad::setBiquad(int type, double Fc, double Q, double peakGainDB) {
+    this->type = type;
+    this->Q = Q;
+    this->Fc = Fc;
+    startFc = Fc;
+    startQ = Q;
+    startPeakGain = peakGainDB;
+    setPeakGain(peakGainDB);
+}
+
+void Biquad::calcBiquad(void) {
+    double norm;
+    double V = pow(10, fabs(peakGain) / 20.0);
+    double K = tan(M_PI * Fc);
+    switch (this->type) {
+        case bq_type_lowpass:
+            norm = 1 / (1 + K / Q + K * K);
+            a0 = K * K * norm;
+            a1 = 2 * a0;
+            a2 = a0;
+            b1 = 2 * (K * K - 1) * norm;
+            b2 = (1 - K / Q + K * K) * norm;
+            break;
+            
+        case bq_type_highpass:
+            norm = 1 / (1 + K / Q + K * K);
+            a0 = 1 * norm;
+            a1 = -2 * a0;
+            a2 = a0;
+            b1 = 2 * (K * K - 1) * norm;
+            b2 = (1 - K / Q + K * K) * norm;
+            break;
+            
+        case bq_type_bandpass:
+            norm = 1 / (1 + K / Q + K * K);
+            a0 = K / Q * norm;
+            a1 = 0;
+            a2 = -a0;
+            b1 = 2 * (K * K - 1) * norm;
+            b2 = (1 - K / Q + K * K) * norm;
+            break;
+            
+        case bq_type_notch:
+            norm = 1 / (1 + K / Q + K * K);
+            a0 = (1 + K * K) * norm;
+            a1 = 2 * (K * K - 1) * norm;
+            a2 = a0;
+            b1 = a1;
+            b2 = (1 - K / Q + K * K) * norm;
+            break;
+            
+        case bq_type_peak:
+            if (peakGain >= 0) {    // boost
+                norm = 1 / (1 + 1/Q * K + K * K);
+                a0 = (1 + V/Q * K + K * K) * norm;
+                a1 = 2 * (K * K - 1) * norm;
+                a2 = (1 - V/Q * K + K * K) * norm;
+                b1 = a1;
+                b2 = (1 - 1/Q * K + K * K) * norm;
+            }
+            else {    // cut
+                norm = 1 / (1 + V/Q * K + K * K);
+                a0 = (1 + 1/Q * K + K * K) * norm;
+                a1 = 2 * (K * K - 1) * norm;
+                a2 = (1 - 1/Q * K + K * K) * norm;
+                b1 = a1;
+                b2 = (1 - V/Q * K + K * K) * norm;
+            }
+            break;
+        case bq_type_lowshelf:
+            if (peakGain >= 0) {    // boost
+                norm = 1 / (1 + sqrt(2) * K + K * K);
+                a0 = (1 + sqrt(2*V) * K + V * K * K) * norm;
+                a1 = 2 * (V * K * K - 1) * norm;
+                a2 = (1 - sqrt(2*V) * K + V * K * K) * norm;
+                b1 = 2 * (K * K - 1) * norm;
+                b2 = (1 - sqrt(2) * K + K * K) * norm;
+            }
+            else {    // cut
+                norm = 1 / (1 + sqrt(2*V) * K + V * K * K);
+                a0 = (1 + sqrt(2) * K + K * K) * norm;
+                a1 = 2 * (K * K - 1) * norm;
+                a2 = (1 - sqrt(2) * K + K * K) * norm;
+                b1 = 2 * (V * K * K - 1) * norm;
+                b2 = (1 - sqrt(2*V) * K + V * K * K) * norm;
+            }
+            break;
+        case bq_type_highshelf:
+            if (peakGain >= 0) {    // boost
+                norm = 1 / (1 + sqrt(2) * K + K * K);
+                a0 = (V + sqrt(2*V) * K + K * K) * norm;
+                a1 = 2 * (K * K - V) * norm;
+                a2 = (V - sqrt(2*V) * K + K * K) * norm;
+                b1 = 2 * (K * K - 1) * norm;
+                b2 = (1 - sqrt(2) * K + K * K) * norm;
+            }
+            else {    // cut
+                norm = 1 / (V + sqrt(2*V) * K + K * K);
+                a0 = (1 + sqrt(2) * K + K * K) * norm;
+                a1 = 2 * (K * K - 1) * norm;
+                a2 = (1 - sqrt(2) * K + K * K) * norm;
+                b1 = 2 * (K * K - V) * norm;
+                b2 = (V - sqrt(2*V) * K + K * K) * norm;
+            }
+            break;
+    }
+    
+    return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/Biquad.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,99 @@
+//
+//  Biquad.h
+//
+//  Created by Nigel Redmon on 11/24/12
+//  EarLevel Engineering: earlevel.com
+//  Copyright 2012 Nigel Redmon
+//
+//  For a complete explanation of the Biquad code:
+//  http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/
+//
+//  License:
+//
+//  This source code is provided as is, without warranty.
+//  You may copy and distribute verbatim copies of this document.
+//  You may modify and use this source code to create binary code
+//  for your own purposes, free or commercial.
+//
+
+#ifndef Biquad_h
+#define Biquad_h
+
+enum {
+    bq_type_lowpass = 0,
+    bq_type_highpass,
+    bq_type_bandpass,
+    bq_type_notch,
+    bq_type_peak,
+    bq_type_lowshelf,
+    bq_type_highshelf
+};
+
+class Biquad {
+public:
+    Biquad();
+    Biquad(int type, double Fc, double Q, double peakGainDB);
+    ~Biquad();
+    void setType(int type);
+    void setQ(double Q);
+    void setFc(double Fc);
+    void setPeakGain(double peakGainDB);
+    void setBiquad(int type, double Fc, double Q, double peakGain);
+    float process(float in);
+    
+    double getQ();
+    double getFc();
+    double getPeakGain();
+
+    double getStartingQ();
+	double getStartingFc();
+	double getStartingPeakGain();
+
+protected:
+    void calcBiquad(void);
+
+    int type;
+    double a0, a1, a2, b1, b2;
+    double Fc, Q, peakGain;
+    double startFc, startQ, startPeakGain;
+    double z1, z2;
+};
+
+inline double Biquad::getQ()
+{
+	return Q;
+}
+
+inline double Biquad::getFc()
+{
+	return Fc;
+}
+
+inline double Biquad::getPeakGain()
+{
+	return peakGain;
+}
+
+inline double Biquad::getStartingQ()
+{
+	return startQ;
+}
+
+inline double Biquad::getStartingFc()
+{
+	return startFc;
+}
+
+inline double Biquad::getStartingPeakGain()
+{
+	return startPeakGain;
+}
+
+inline float Biquad::process(float in) {
+    double out = in * a0 + z1;
+    z1 = in * a1 + z2 - b1 * out;
+    z2 = in * a2 - b2 * out;
+    return out;
+}
+
+#endif // Biquad_h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/DBoxSynth.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,35 @@
+/*
+ * SimpleSynth.h
+ *
+ *  Created on: Oct 22, 2013
+ *      Author: Victor Zappi
+ */
+
+#ifndef DBOXSYNTH_H_
+#define DBOXSYNTH_H_
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Synth.h"
+
+
+class DBoxSynth : public Synth
+{
+public:
+	DBoxSynth(unsigned int rate, unsigned long buffer_size);
+	double getSample();
+	double *getBlock(int block_size);
+
+
+private:
+	Sampler *smp;
+
+};
+
+
+
+
+#endif /* DBOXSYNTH_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/DboxSensors.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,157 @@
+/*
+ * DboxSensors.cpp
+ *
+ *  Created on: May 19, 2014
+ *      Author: Victor Zappi
+ */
+
+
+#include "DboxSensors.h"
+#include "config.h"
+
+using namespace std;
+
+
+
+int DboxSensors::initSensors(int tk0_bus, int tk0_address, int tk1_bus, int tk1_address, int tk_file, int fsr_pin, int fsrmax, bool useNewSensors, int gpio_0, int gpio_1)
+{
+	newSensors = useNewSensors;
+	// init first touch key on i2c bus
+	if(tk0_address >= 0) {
+		if(TK0.initI2C_RW(tk0_bus, tk0_address, tk_file)>0)
+			return 1;
+		if(TK0.initTouchKey(newSensors)>0)
+			return 2;
+	}
+
+	// init second touch key on i2c bus
+	if(tk1_address >= 0) {
+		if(TK1.initI2C_RW(tk1_bus, tk1_address, tk_file)>0)
+			return 1;
+		if(TK1.initTouchKey(newSensors)>0)
+			return 2;
+	}
+
+	// init fsr on analog input pin
+	fsr_pinNum	= fsr_pin;
+	fsr_max	  	= fsrmax;
+
+	if(FSR.initAnalogInputs()>0)
+		return 3;
+
+	gpio[0] = gpio_0;
+	if(gpio[0]!=-1)
+	{
+		fdDi[0] = gpio_export(gpio[0]);
+		if(fdDi[0] == -1)
+			return 4;
+	}
+	digitalIn[0] = 1;
+
+	return 0;
+}
+
+
+int DboxSensors::readSensors()
+{
+	// write data into first touch key
+	if(TK0.ready()) {
+		if(TK0.readI2C()>0)
+			return 1;
+
+		// retrieve data from first touch key
+		tk0_touchCnt = TK0.getTouchCount();
+	}
+	else
+		tk0_touchCnt = 0;
+
+	// write data into second touch key
+	if(TK1.ready()) {
+		if(TK1.readI2C()>0)
+			return 1;
+		// retrieve data from second touch key
+		tk1_touchCnt = TK1.getTouchCount();
+	}
+	else
+		tk1_touchCnt = 0;
+
+
+	int max = 3;
+	if(newSensors)
+		max = 5;
+	// if touches detected on main touch key
+	if(tk0_touchCnt == 0 && tk1_touchCnt == 0)
+		resetSensorsData();
+	else
+	{
+		for(int i=0; i<max; i++)
+		{
+			tk0_touchPosX[i] = TK0.getSliderPosition()[i];
+			tk0_touchSize[i] = TK0.getSlidersize()[i];
+
+			tk1_touchPosX[i] = TK1.getSliderPosition()[i];
+			tk1_touchSize[i] = TK1.getSlidersize()[i];
+		}
+		tk0_touchPosY 	 = TK0.getSliderPositionH();
+		tk1_touchPosY 	 = TK1.getSliderPositionH();
+		fsr_read		 = (double)FSR.read(fsr_pinNum);
+	}
+
+	if(gpio[0]!=-1)
+	{
+		if(gpio_read(fdDi[0], &digitalIn[0])==-1)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+
+DboxSensors::DboxSensors()
+{
+	resetSensorsData();
+}
+
+
+
+DboxSensors::~DboxSensors()
+{
+	if(gpio[0]!=-1)
+		gpio_dismiss(fdDi[0], gpio[0]);
+}
+
+
+
+//--------------------------------------------------------------------------------------------------------
+// private methods
+//--------------------------------------------------------------------------------------------------------
+
+// idle values
+void DboxSensors::resetSensorsData()
+{
+	int max = 3;
+	if(newSensors)
+		max = 5;
+
+	for(int i=0; i<max; i++)
+	{
+		tk0_touchPosX[i] = -1;
+		tk0_touchPosY	 = -1;
+		tk0_touchSize[i] = 0;
+
+		tk1_touchPosX[i] = -1;
+		tk1_touchPosY	 = -1;
+		tk1_touchSize[i] = 0;
+
+		fsr_read		 = 0;
+	}
+
+	return;
+}
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/DboxSensors.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,128 @@
+/*
+ * DboxSensors.h
+ *
+ *  Created on: May 19, 2014
+ *      Author: Victor Zappi
+ */
+
+#ifndef DBOXSENSORS_H_
+#define DBOXSENSORS_H_
+
+#include <stdio.h>
+#include <sys/mount.h>	// mount()
+#include <string.h> 	// strerror()
+#include <fstream> 		// fstream
+#include <iostream>
+#include <unistd.h> 	// usleep()
+#include <glob.h>		// glob()
+#include <sys/time.h>	// elapsed time
+#include <sys/stat.h>	// mkdir()
+#include <algorithm>	// reverse() [string...]
+
+#include "I2c_TouchKey.h"
+#include "AnalogInput.h"
+#include "../../include/GPIOcontrol.h"	// TODO wrap this into a class
+
+/*---------------------------------------------------------------------------------------------------------------------------------------------------
+ * This class retrieves data from all the connected sensors,
+ * logs them
+ * and exposes to the main only the values needed to synthesize sound
+ *
+ * The simple instrument has:
+ *
+ *
+ *
+ *---------------------------------------------------------------------------------------------------------------------------------------------------
+ */
+class DboxSensors
+{
+public:
+	int initSensors(int tk0_bus, int tk0_address, int tk1_bus, int tk1_address, int tk_file, int fsr_pin, int fsrmax, bool useNewSensors, int gpio0=-1, int gpio1=-1);
+	int readSensors();
+	int getTKTouchCount(int index);
+	float *getTKXPositions(int index);
+	float getTKYPosition(int index);
+	float *getTKTouchSize(int index);
+	double getFSRVAlue();
+	int getDigitalIn(int index);
+
+	DboxSensors();
+	~DboxSensors();
+
+private:
+	bool newSensors;
+
+	I2c_TouchKey TK0;
+	int tk0_touchCnt;
+	float tk0_touchPosX[5];
+	float tk0_touchPosY;
+	float tk0_touchSize[5];
+
+	I2c_TouchKey TK1;
+	int tk1_touchCnt;
+	float tk1_touchPosX[5];
+	float tk1_touchPosY;
+	float tk1_touchSize[5];
+
+	AnalogInput FSR;
+	int fsr_pinNum;
+	double fsr_read;
+	int fsr_max;
+
+	unsigned int digitalIn[2];
+	int fdDi[2];
+	int gpio[2];
+
+	void resetSensorsData();
+
+};
+
+
+
+//--------------------------------------------------------------------------------
+// read interface
+inline int DboxSensors::getTKTouchCount(int index)
+{
+	if(index==0)
+		return tk0_touchCnt;
+	else
+		return tk1_touchCnt;
+}
+
+inline float *DboxSensors::getTKXPositions(int index)
+{
+	if(index==0)
+		return tk0_touchPosX;
+	else
+		return tk1_touchPosX;
+}
+
+inline float DboxSensors::getTKYPosition(int index)
+{
+	if(index==0)
+		return tk0_touchPosY;
+	else
+		return tk1_touchPosY;
+}
+
+inline float *DboxSensors::getTKTouchSize(int index)
+{
+	if(index==0)
+		return tk0_touchSize;
+	else
+		return tk1_touchSize;
+}
+
+inline double DboxSensors::getFSRVAlue()
+{
+	return fsr_read;
+}
+
+inline int DboxSensors::getDigitalIn(int index)
+{
+	return digitalIn[index];
+}
+//--------------------------------------------------------------------------------
+
+
+#endif /* DBOXSENSORS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/FIRfilter.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,73 @@
+/*
+ * FIRfilter.h
+ *
+ *  Created on: Aug 5, 2014
+ *      Author: Victor Zappi and Andrew McPherson
+ */
+
+#ifndef FIRFILTER_H_
+#define FIRFILTER_H_
+
+
+#include <NE10.h>
+
+//#define FILTER_TAP_NUM 21
+//ne10_float32_t filterTaps[FILTER_TAP_NUM] = {
+//	0.000350,
+//	0.001133,
+//	0.002407,
+//	0.004203,
+//	0.006468,
+//	0.009057,
+//	0.011748,
+//	0.014265,
+//	0.016323,
+//	0.017671,
+//	0.018141,
+//	0.017671,
+//	0.016323,
+//	0.014265,
+//	0.011748,
+//	0.009057,
+//	0.006468,
+//	0.004203,
+//	0.002407,
+//	0.001133,
+//	0.000350
+//};
+#define FILTER_TAP_NUM 31
+ne10_float32_t filterTaps[FILTER_TAP_NUM] = {
+		0.000018,
+		0.000043,
+		0.000078,
+		0.000125,
+		0.000183,
+		0.000252,
+		0.000330,
+		0.000415,
+		0.000504,
+		0.000592,
+		0.000677,
+		0.000754,
+		0.000818,
+		0.000866,
+		0.000897,
+		0.000907,
+		0.000897,
+		0.000866,
+		0.000818,
+		0.000754,
+		0.000677,
+		0.000592,
+		0.000504,
+		0.000415,
+		0.000330,
+		0.000252,
+		0.000183,
+		0.000125,
+		0.000078,
+		0.000043,
+		0.000018
+};
+
+#endif /* FIRFILTER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/FeedbackOscillator.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,112 @@
+/*
+ * FeedbackOscillator.cpp
+ *
+ * Recursive phase-shift oscillator implemented
+ * on the matrix
+ *
+ * Andrew McPherson 2014
+ */
+
+#include "FeedbackOscillator.h"
+#include <cstdlib>
+#include <cmath>
+
+#define COEFF_B0 	0
+#define COEFF_B1	1
+#define COEFF_A1	2
+
+FeedbackOscillator::FeedbackOscillator()
+: wavetable1(0), wavetable2(0)
+{
+
+}
+
+FeedbackOscillator::~FeedbackOscillator() {
+	if(wavetable1 != 0)
+		free(wavetable1);
+	if(wavetable2 != 0)
+		free(wavetable2);
+
+}
+
+// Initialise the settings for the feedback oscillator
+void FeedbackOscillator::initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate) {
+	wavetableMaxLength = maxTableSize;
+	if(wavetable1 != 0)
+		free(wavetable1);
+	if(wavetable2 != 0)
+		free(wavetable2);
+
+	wavetable1 = (float *)malloc(maxTableSize * sizeof(float));
+	wavetable2 = (float *)malloc(maxTableSize * sizeof(float));
+
+	float omega = tan(M_PI * hpfCutoffFrequency / matrixSampleRate);
+	float n = 1.0f / (1.0f + omega);
+
+	coeffs[COEFF_A1] = (omega - 1.0f) * n;
+	coeffs[COEFF_B0] = n;
+	coeffs[COEFF_B1] = -n;
+
+	for(int n = 0; n < maxTableSize; n++)
+		wavetable1[n] = wavetable2[n] = 0;
+
+	wavetableRead = wavetable1;
+	wavetableWrite = wavetable2;
+	wavetableWritePointer = 0;
+	sampleCount = lastTriggerCount = 0;
+}
+
+// Process one sample and store the output value
+// Returns true if the wavetable needs rendering
+int FeedbackOscillator::process(uint16_t input, uint16_t *output) {
+	float inFloat = input / 65536.0;
+	float outFloat = coeffs[COEFF_B0] * inFloat + coeffs[COEFF_B1] * lastInput - coeffs[COEFF_A1] * lastOutput;
+	int requestRenderLength = 0;
+
+	//outFloat *= 2.0;
+
+	int intOut = outFloat * 65536.0 + 32768;
+	if(intOut > 65535)
+		intOut = 65535;
+	if(intOut < 0)
+		intOut = 0;
+	//intOut = (intOut & 0xFF) << 8;
+	//if(intOut > 65535)
+	//	intOut = 65535;
+
+	*output = (uint16_t)intOut;
+
+	if(canTrigger && outFloat > 0 && lastOutput <= 0) {
+		triggered = true;
+		requestRenderLength = wavetableWritePointer;	// How many samples stored thus far?
+		if(requestRenderLength < 4)
+			requestRenderLength = 0;	// Ignore anything with fewer than 4 points
+
+		lastTriggerCount = sampleCount;
+		canTrigger = false;
+		wavetableWritePointer = 0;
+
+		// Swap buffers
+		float *temp = wavetableWrite;
+		wavetableWrite = wavetableRead;
+		wavetableRead = temp;
+	}
+
+	if(triggered) {
+		wavetableWrite[wavetableWritePointer] = outFloat;
+		if(++wavetableWritePointer >= wavetableMaxLength) {
+			triggered = false;
+			wavetableWritePointer = 0;
+		}
+	}
+
+	if(sampleCount - lastTriggerCount > 40)
+		canTrigger = true;
+
+	sampleCount++;
+
+	lastOutput = outFloat;
+	lastInput = inFloat;
+
+	return requestRenderLength;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/FeedbackOscillator.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,43 @@
+/*
+ * FeedbackOscillator.h
+ *
+ *  Created on: June 8, 2014
+ *      Author: Andrew McPherson
+ */
+
+#ifndef FEEDBACKOSCILLATOR_H
+#define FEEDBACKOSCILLATOR_H
+
+#include <stdint.h>
+
+class FeedbackOscillator
+{
+public:
+	FeedbackOscillator();
+	~FeedbackOscillator();
+
+	// Initialise the settings for the feedback oscillator
+	void initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate);
+
+	// Process one sample and store the output value
+	// Returns the length of table to interpolate; or 0 if nothing to process further
+	int process(uint16_t input, uint16_t *output);
+
+	float *wavetable() { return wavetableRead; }
+
+private:
+	float coeffs[3];			// Coefficients of first-order high-pass filter
+	float lastInput;			// last input sample for HPF
+	float lastOutput;			// last output sample of HPF
+	bool triggered;				// whether we are currently saving samples
+	bool canTrigger;			// whether we are able to begin saving samples
+	int wavetableMaxLength;		// how long the stored wavetable can be
+	int sampleCount;			// how many samples have elapsed
+	int lastTriggerCount;		// sample count when we last triggered
+
+	float *wavetable1, *wavetable2;			// Two wavetables where we record samples
+	float *wavetableRead, *wavetableWrite;	// Pointers to the above wavetables
+	int wavetableWritePointer;				// Where we are currently writing
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/I2c_TouchKey.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,152 @@
+/*
+ * I2c_TouchKey.cpp
+ *
+ *  Created on: Oct 14, 2013
+ *      Author: Victor Zappi
+ */
+
+
+
+#include "I2c_TouchKey.h"
+
+#undef DEBUG_I2C_TOUCHKEY
+
+I2c_TouchKey::I2c_TouchKey()
+{
+	isReady = false;
+	newSensor = false;
+	touchCount = 0;
+	sliderSize[0] = sliderSize[1] = sliderSize[2] = -1;
+	sliderPosition[0] = sliderPosition[1] = sliderPosition[2] = -1;
+	sliderPositionH = -1;
+}
+
+int I2c_TouchKey::initTouchKey(bool useNewSensor)
+{
+	newSensor = useNewSensor;
+	numBytesToRead = newSensor ? NUM_BYTES_NEW : NUM_BYTES_OLD;
+
+	char buf[3] = { 0x00, 0x01, 0x00 }; // code for centroid mode
+	if(write(i2C_file, buf, 3) !=3)
+	{
+		cout << "Failed to set TouchKey in \"Centroid Mode\" " << endl;
+		return 1;
+	}
+
+	usleep(5000); // need to give TouchKey enough time to process command
+
+	char buf4[4] = { 0x00, 0x07, 0x00, 0x64}; // code for change minimum touch area
+	if(write(i2C_file, buf4, 4) !=4)
+	{
+		cout << "Failed to set TouchKey minimum touch size" << endl;
+		return 1;
+	}
+
+	usleep(5000); // need to give TouchKey enough time to process command
+
+	buf[0] = 0x06; // code for data collection
+	if(write(i2C_file, buf, 1) !=1)
+	{
+		cout << "Failed to prepare data collection " << endl;
+		return 2;
+	}
+
+	usleep(5000); // need to give TouchKey enough time to process command
+
+	isReady = true;
+
+	return 0;
+}
+
+
+int I2c_TouchKey::readI2C()
+{
+	bytesRead = read(i2C_file, dataBuffer, numBytesToRead);
+	if (bytesRead != numBytesToRead)
+	{
+		cout << "Failure to read Byte Stream" << endl;
+		return 2;
+	}
+	/*cout << NUM_BYTES << " bytes read" << endl;
+	for(int j=0; j<9; j++)
+		cout << "\t" << (int)dataBuffer[j];
+	cout << endl;
+	*/
+
+	touchCount = 0;
+
+	rawSliderPosition[0] = (((dataBuffer[0] & 0xF0) << 4) + dataBuffer[1]);
+	rawSliderPosition[1] = (((dataBuffer[0] & 0x0F) << 8) + dataBuffer[2]);
+	rawSliderPosition[2] = (((dataBuffer[3] & 0xF0) << 4) + dataBuffer[4]);
+
+	// Old TouchKeys sensors have 3 touch locations plus horizontal positions
+	// New D-Box sensors have 5 touch locations but no horizontal position
+	if(newSensor)
+	{
+		rawSliderPosition[3] = (((dataBuffer[5] & 0xF0) << 4) + dataBuffer[6]);
+		rawSliderPosition[4] = (((dataBuffer[5] & 0x0F) << 8) + dataBuffer[7]);
+		rawSliderPositionH = 0x0FFF;
+	}
+	else
+	{
+		rawSliderPosition[3] = 0x0FFF;
+		rawSliderPosition[4] = 0x0FFF;
+		rawSliderPositionH   = (((dataBuffer[3] & 0x0F) << 8) + dataBuffer[5]);
+	}
+
+
+	for(int i = 0; i < 5; i++)
+	{
+		if(rawSliderPosition[i] != 0x0FFF) // 0x0FFF means no touch
+		{
+			//sliderPosition[i] = (float)rawSliderPosition[i] / 1536.0;	// Black keys, vertical (128 * 12)
+			//sliderPosition[i] = (float)rawSliderPosition[i] / 768.0;	// Cute white key, for simple instrument
+			if(newSensor)
+				sliderPosition[i] = (float)rawSliderPosition[i] / 3200.0;   // New sensors; 26 pads (128 * 25)
+			else
+				sliderPosition[i] = (float)rawSliderPosition[i] / 2432.0;	// White keys, vertical (128 * 19)
+			if(sliderPosition[i]>1.0)
+				sliderPosition[i] = 1.0;
+			if(newSensor)
+				sliderSize[i]     = (float)dataBuffer[i + 8] / 255.0;
+			else {
+				if(i < 3)
+					sliderSize[i]     = (float)dataBuffer[i + 6] / 255.0;
+				else
+					sliderSize[i]     = 0.0;
+			}
+			touchCount++;
+		}
+		else {
+			sliderPosition[i] = -1.0;
+			sliderSize[i]     = 0.0;
+		}
+	}
+
+
+
+	if(rawSliderPositionH != 0x0FFF)
+	{
+		sliderPositionH = (float)rawSliderPositionH / 256.0;			// White keys, horizontal (1 byte + 1 bit)
+	}
+	else
+		sliderPositionH = -1.0;
+
+#ifdef DEBUG_I2C_TOUCHKEY
+	for(int i = 0; i < bytesRead; i++) {
+		printf("%2X ", dataBuffer[i]);
+	}
+	cout << touchCount << " touches: ";
+	for(int i = 0; i < touchCount; i++) {
+		cout << "(" << sliderPosition[i] << ", " << sliderSize[i] << ") ";
+	}
+	cout << "H = " << sliderPositionH << endl;
+#endif
+
+	return 0;
+}
+
+
+I2c_TouchKey::~I2c_TouchKey()
+{}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/I2c_TouchKey.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,75 @@
+/*
+ * I2c.h
+ *
+ *  Created on: Oct 14, 2013
+ *      Author: Victor Zappi
+ */
+
+#ifndef I2CTK_H_
+#define I2CTK_H_
+
+#include "../../include/I2c.h"
+
+#define NUM_BYTES_OLD 9
+#define NUM_BYTES_NEW 13
+
+class I2c_TouchKey : public I2c
+{
+private:
+	bool isReady;
+	bool newSensor;
+	int numBytesToRead;
+
+	// read NUM_BYTES bytes, which have to be properly parsed
+	char dataBuffer[NUM_BYTES_NEW];
+	int bytesRead;
+
+	int rawSliderPosition[5];
+	int rawSliderPositionH;
+
+	int touchCount;
+	float sliderSize[5];
+	float sliderPosition[5];
+	float sliderPositionH;
+
+
+public:
+	int initTouchKey(bool useNewSensor = false);
+	int readI2C();
+	int getTouchCount();
+	float * getSlidersize();
+	float * getSliderPosition();
+	float getSliderPositionH();
+
+	bool ready() { return isReady; }
+
+	I2c_TouchKey();
+	~I2c_TouchKey();
+
+};
+
+inline int I2c_TouchKey::getTouchCount()
+{
+	return touchCount;
+}
+
+inline float * I2c_TouchKey::getSlidersize()
+{
+	return sliderSize;
+}
+
+inline float * I2c_TouchKey::getSliderPosition()
+{
+	return sliderPosition;
+}
+
+inline float I2c_TouchKey::getSliderPositionH()
+{
+	return sliderPositionH;
+}
+
+
+
+
+
+#endif /* I2CTK_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/OscillatorBank.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,1016 @@
+/*
+ * OscillatorBank.cpp
+ *
+ *  Created on: May 23, 2014
+ *      Author: Victor Zappi and Andrew McPherson
+ */
+
+
+/*
+ * There is a problem with name consistency between this class and the Parser class in spear_parser files.
+ * There, a "frame" is each of the time values where partials are sampled, while a "hop" is the actual jump between frames [calculated in samples]
+ * Here, "hop" is used with the meaning of "frame", while "frame" became the local frame of a partial
+ *
+ * example
+ *
+ * frames:	0		1		2
+ * p0				p0_0 	p0_1
+ * p1		p1_0	p1_1 	p1_2
+ * p2		p2_0	p2_1
+ *
+ * 	In this case:
+ * 		 in Parser there are 2 hops, 3 total frames and the 3 partials have respectively 2, 3 and 2 local frames
+ *
+ * 		 here there are 3 total hops [the concept of jumps is discarded, cos not in use] and the 3 partials have respectively 2, 3 and 2 frames
+ *
+ * 	This must be fixed
+*/
+
+// TODO: fix hop-frame name consistency
+
+
+#include <stdlib.h>
+
+#include "OscillatorBank.h"
+
+OscillatorBank::OscillatorBank() {
+	loaded = false;
+}
+
+OscillatorBank::OscillatorBank(string filename, int hopsize, int samplerate) {
+	loaded = false;
+	loadFile(filename.c_str(), hopsize, samplerate);
+}
+
+OscillatorBank::OscillatorBank(char *filename, int hopsize, int samplerate) {
+	loaded = false;
+	loadFile(filename, hopsize, samplerate);
+}
+
+OscillatorBank::~OscillatorBank() {
+	free(oscillatorPhases);
+	free(oscillatorNextNormFreq);
+	free(oscillatorNextAmp);
+	free(oscillatorNormFrequencies);
+	free(oscillatorAmplitudes);
+	free(oscillatorNormFreqDerivatives);
+	free(oscillatorAmplitudeDerivatives);
+	free(phaseCopies);
+	free(nextNormFreqCopies);
+	free(nextAmpCopies);
+
+	delete[] oscStatNormFrequenciesMean;
+	delete[] oscStatNumHops;
+	delete[] lookupTable;
+	delete[] indicesMapping;
+	delete[] freqFixedDeltas;
+	delete[] ampFixedDeltas;
+	delete[] nyquistCut;
+}
+
+bool OscillatorBank::initBank(int oversamp) {
+	if (!loaded)
+		return false;
+
+	//---prepare look-up table
+	lookupTableSize = 1024;
+	lookupTable		= new float[lookupTableSize + 1];
+	for (int n = 0; n < (lookupTableSize + 1); n++)
+		lookupTable[n] = sin(2.0 * M_PI * (float) n / (float) lookupTableSize);
+	frequencyScaler = (float) lookupTableSize / rate;
+	nyqNorm			= rate / 2 * frequencyScaler;
+
+	if (oversamp < 1)
+		oversamp = 1;
+
+	//---prepare oscillators
+	partials = &(parser.partials); // pointer to paser's partials
+	partialsHopSize = parser.getHopSize();
+	lastHop = partials->getHopNum(); // last bank hop is equal to last partial frame, which is equal to partial hop num
+	overSampling = oversamp;
+	hopSize = partialsHopSize / overSampling; // if oversampling, osc bank hop num > partials hop num
+	hopSizeReminder = partialsHopSize % overSampling;
+	oscBankHopSize = hopSize;
+	numOfPartials = partials->getPartialNum();
+	numOfOscillators = partials->getMaxActivePartialNum(); // get the maximum number of active partials at the same time
+
+	// set to next multiple of 4 [NEON]
+	numOfOscillators = (numOfOscillators + 3) & ~0x3; // to be sure we can add up to 3 fake oscillators
+
+	int err;
+	//---allocate buffers
+	// alligned buffers [NEON]
+	err = posix_memalign((void**) &oscillatorPhases, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &oscillatorNextNormFreq, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &oscillatorNextAmp, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &oscillatorNormFrequencies, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &oscillatorAmplitudes, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &oscillatorNormFreqDerivatives, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &oscillatorAmplitudeDerivatives, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &phaseCopies, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &nextNormFreqCopies, 16,
+			numOfOscillators * sizeof(float));
+	err += posix_memalign((void**) &nextAmpCopies, 16,
+			numOfOscillators * sizeof(float));
+
+	// regular ones
+	oscStatNormFrequenciesMean	= new float[numOfPartials];
+	oscStatNumHops				= new float[numOfPartials];
+	indicesMapping				= new int[numOfPartials];
+	freqFixedDeltas				= new float[numOfPartials];
+	ampFixedDeltas				= new float[numOfPartials];
+	nyquistCut 					= new bool[numOfPartials];
+
+	if (err > 0) {
+		dbox_printf("Failed memory allocations %@#!\n");
+		return false;
+	}
+
+	// copy stats [they do not change]
+	for (int n = 0; n < numOfPartials; n++) {
+		oscStatNormFrequenciesMean[n] = partials->partialFreqMean[n]
+				* frequencyScaler;
+		oscStatNumHops[n] = partials->partialNumFrames[n]; // in Parser and Partials "frames" are what we call here "hops" [see comment at top of file]
+	}
+
+	// deafult values
+	actPartNum		= 0;
+	loopStartHop	= 0;
+	loopEndHop		= (parser.partials.getHopNum() - 2) * overSampling;
+	ampTh			= 0.0001;
+	hopNumTh		= 0;
+	pitchMultiplier = 1;
+	freqMovement	= 1;
+	filterNum		= 0;
+	note			= false;
+	speed			= 1;
+	nextSpeed		= -1;
+	maxSpeed 		= 10;
+	minSpeed 		= 0.1;
+	jumpHop 		= -1;
+
+	// filter
+	filterMaxF		= 22000;
+	filterAmpMinF	= 10 * frequencyScaler;
+	filterAmpMaxF	= 5000 * frequencyScaler;
+	filterAmpMul	= 10.0;
+
+	// adsr
+	minAttackTime	= .0001;
+	deltaAttackTime = 2.;
+	minReleaseTime	= 1;
+	deltaReleaseTime = 2.5;
+
+	adsr.setAttackRate(minAttackTime * rate);
+	adsr.setDecayRate(.0001 * rate);
+	adsr.setSustainLevel(1);
+	adsr.setReleaseRate(minReleaseTime * rate);
+
+	state = bank_stopped;
+	return true;
+}
+
+void OscillatorBank::resetOscillators() {
+	currentHop			= -1;
+	loopDir				= 1;
+	loopDirShift 		= 0;
+	fill(nyquistCut, nyquistCut + numOfPartials, false);
+	prevAdsrVal			= 0;
+	prevAmpTh			= ampTh;
+	prevHopNumTh		= hopNumTh;
+	prevPitchMultiplier = pitchMultiplier;
+	prevFreqMovement 	= freqMovement;
+	prevFilterNum = filterNum;
+	memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float));
+	memcpy(prevFilterQ, filterQ, filterNum * sizeof(float));
+
+	int activePNum		= partials->activePartialNum[0];
+	unsigned int *activeP = partials->activePartials[0];
+	for (int i = 0; i < activePNum; i++) {
+		freqFixedDeltas[activeP[i]] = partials->partialFreqDelta[activeP[i]][0]
+				/ overSampling;
+		ampFixedDeltas[activeP[i]]	= partials->partialAmpDelta[activeP[i]][0]
+				/ overSampling;
+	}
+	// attack!
+	adsr.gate(1);
+	note = true;
+
+	nextHop();
+
+	state = bank_playing;
+}
+
+void OscillatorBank::nextHop() {
+	hopSize = oscBankHopSize;
+
+	// copy phases, next freqs and next amps from previous frame
+	memcpy(phaseCopies, oscillatorPhases, actPartNum * sizeof(float));
+	memcpy(nextNormFreqCopies, oscillatorNextNormFreq,
+			actPartNum * sizeof(float));
+	memcpy(nextAmpCopies, oscillatorNextAmp, actPartNum * sizeof(float));
+
+	// next frame is forward or backwards, cos we could be in the loop
+	currentHop += loopDir;
+
+	checkDirection();
+
+//	if((currentHop/overSampling)%100 == 0)
+//		dbox_printf("currentHop %d, direction: %d\n", currentHop/overSampling, loopDir);
+
+	// if needs jump, end here this method, cos jumpToHop() will do tee rest
+	if (checkJump() == 0)
+		return;
+	// otherwise, if jump is not needed or fails, continue regular stuff
+
+	if (nextEnvState() != 0)
+		return; // release has ended!
+
+	checkSpeed();
+
+	// now let's decide how to calculate next hop
+	if (!checkOversampling())
+		nextOscBankHop();
+	else
+		nextPartialHop();
+}
+
+void OscillatorBank::nextOscBankHop() {
+	int parIndex, localHop;
+	float parDamp = 1;
+	int currentPartialHop = (currentHop / overSampling) + loopDirShift;
+
+	// if going backwards in the loop, get previous frame active partials...
+	actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift];
+	actPart = partials->activePartials[currentPartialHop - loopDirShift];
+	//cout << "actPartNum: " << actPartNum << endl;
+
+	envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release]
+
+	int parCnt = 0;
+	int currentHopReminder = currentHop % overSampling;
+	// steps to reach next bank hop from previous partial hop
+	int steps = currentHopReminder + 1;
+	if (loopDir < 0)
+		steps = overSampling - currentHopReminder + 1;
+
+	for (int i = 0; i < actPartNum; i++) {
+		// find partial and frame
+		parIndex = actPart[i];
+		//localHop	= partials->localPartialFrames[currentPartialHop][parIndex];
+		localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
+
+		//float delta = partials->partialFrequencies[parIndex][localHop+loopDir] - partials->partialFrequencies[parIndex][localHop];
+
+		// if this partial was over nyquist on previous hop...
+		if (nyquistCut[parIndex]) {
+			// ...restart from safe values
+			oscillatorPhases[parCnt] = 0;
+			//TODO add freqmove dependency
+			oscillatorNextNormFreq[parCnt] =
+					(partials->partialFrequencies[parIndex][localHop]
+							+ freqFixedDeltas[parIndex] * (steps - 1))
+							* frequencyScaler * prevPitchMultiplier;
+			oscillatorNextAmp[parCnt] = 0;
+		} else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame
+				{
+			if ((localHop != 0) || (currentHopReminder != 0)) {
+				oscillatorPhases[parCnt] =
+						phaseCopies[indicesMapping[parIndex]];
+				oscillatorNextNormFreq[parCnt] =
+						nextNormFreqCopies[indicesMapping[parIndex]];
+				oscillatorNextAmp[parCnt] =
+						nextAmpCopies[indicesMapping[parIndex]];
+			} else // first oscillator hop [both for bank and partial], so no previous data are available
+			{
+				oscillatorPhases[parCnt] = 0;
+				//TODO add freqmove dependency
+				oscillatorNextNormFreq[parCnt] =
+						partials->partialFrequencies[parIndex][localHop]
+								* frequencyScaler * prevPitchMultiplier;
+				parDamp = calculateParDamping(parIndex, prevHopNumTh,
+						prevAdsrVal, oscillatorNextNormFreq[parCnt],
+						prevFilterNum, prevFilterFreqs, prevFilterQ);
+				oscillatorNextAmp[parCnt] =
+						partials->partialAmplitudes[parIndex][localHop]
+								* parDamp;
+				if(oscillatorNextAmp[parCnt] > 1)
+						oscillatorNextAmp[parCnt] = 1;
+				freqFixedDeltas[parIndex] =
+						partials->partialFreqDelta[parIndex][localHop + loopDir]
+								* loopDir / overSampling;
+				ampFixedDeltas[parIndex] =
+						partials->partialAmpDelta[parIndex][localHop + loopDir]
+								* loopDir / overSampling;
+			}
+		} else {
+			oscillatorPhases[parCnt] = phaseCopies[indicesMapping[parIndex]];
+			oscillatorNextNormFreq[parCnt] =
+					nextNormFreqCopies[indicesMapping[parIndex]];
+			oscillatorNextAmp[parCnt] = nextAmpCopies[indicesMapping[parIndex]];
+		}
+
+		// remove aliasing, skipping partial over nyquist freq
+		if (oscillatorNextNormFreq[parCnt] > nyqNorm) {
+			nyquistCut[parIndex] = true;
+			continue;
+		}
+		nyquistCut[parIndex] = false;
+
+		// first set up freq, cos filter affects amplitude damping according to freq content
+		oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts
+		// save next values, current for next round
+		oscillatorNextNormFreq[parCnt] = (freqMovement
+				* (partials->partialFrequencies[parIndex][localHop]
+						+ freqFixedDeltas[parIndex] * steps) * frequencyScaler
+				+ (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
+				* pitchMultiplier;
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
+				- oscillatorNormFrequencies[parCnt]) / hopCounter;
+		// this second weird passage handles dissonance control, morphing between regular and mean frequencies
+		oscillatorNormFreqDerivatives[parCnt] = freqMovement
+				* oscillatorNormFreqDerivatives[parCnt]
+				+ (1 - freqMovement)
+						* ((oscStatNormFrequenciesMean[parIndex]
+								* pitchMultiplier)
+								- oscillatorNormFrequencies[parCnt])
+						/ hopCounter;
+
+		parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
+				oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
+
+		// now amplitudes
+		oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts
+		// save next values, current for next round
+		//delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop];
+		oscillatorNextAmp[parCnt] =
+				(partials->partialAmplitudes[parIndex][localHop]
+						+ ampFixedDeltas[parIndex] * steps) * parDamp;
+		if(oscillatorNextAmp[parCnt] > 1)
+				oscillatorNextAmp[parCnt] = 1;
+		if ((loopDir == -1) && (localHop = 1) && (currentHopReminder == 1))
+			oscillatorNextAmp[parCnt] = 0;
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
+				- oscillatorAmplitudes[parCnt]) / hopCounter;
+
+		// finally update current mapping between oscillators and partials
+		indicesMapping[parIndex] = parCnt;
+		parCnt++;
+	}
+	actPartNum = parCnt;
+	// [NEON] if not multiple of 4...
+	if (actPartNum % 4 != 0)
+		addFakeOsc();
+}
+
+void OscillatorBank::nextPartialHop() {
+	unsigned int parIndex, localHop;
+	float parDamp = 1;
+	int currentPartialHop = currentHop / overSampling;
+
+	// if going backwards in the loop, get previous frame active partials...
+	actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift];
+	actPart    = partials->activePartials[currentPartialHop - loopDirShift];
+
+	envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release]
+
+	int parCnt = 0;
+	int steps = overSampling - 1; // steps to reach next hop [partial or bank] from previous partial hop
+
+	for (int i = 0; i < actPartNum; i++) {
+		// find partial and frame
+		parIndex = actPart[i];
+		//localHop	= partials->localPartialFrames[currentPartialHop][parIndex];
+		localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
+
+		// if this partial was over nyquist on previous hop...
+		if (nyquistCut[parIndex]) {
+			// ...restart from safe values
+			oscillatorPhases[parCnt] = 0;
+			//TODO add freqmove dependency
+			oscillatorNextNormFreq[parCnt] =
+					(partials->partialFrequencies[parIndex][localHop]
+							+ freqFixedDeltas[parIndex] * steps
+									* (1 - loopDirShift)) * frequencyScaler
+							* prevPitchMultiplier;
+			oscillatorNextAmp[parCnt] = 0;
+		} else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame
+		{
+			if ((localHop != 0) || (overSampling > 1)) {
+				oscillatorPhases[parCnt] =
+						phaseCopies[indicesMapping[parIndex]];
+				oscillatorNextNormFreq[parCnt] =
+						nextNormFreqCopies[indicesMapping[parIndex]];
+				oscillatorNextAmp[parCnt] =
+						nextAmpCopies[indicesMapping[parIndex]];
+			} else // first oscillator hop [both for bank and partial], so no previous data are available
+			{
+				oscillatorPhases[parCnt] = 0;
+				//TODO add freqmove dependency
+				oscillatorNextNormFreq[parCnt] =
+						partials->partialFrequencies[parIndex][localHop]
+								* frequencyScaler * prevPitchMultiplier;
+				parDamp = calculateParDamping(parIndex, prevHopNumTh,
+						prevAdsrVal, oscillatorNextNormFreq[parCnt],
+						prevFilterNum, prevFilterFreqs, prevFilterQ);
+				oscillatorNextAmp[parCnt] =
+						partials->partialAmplitudes[parIndex][localHop]
+								* parDamp;
+				if(oscillatorNextAmp[parCnt] > 1)
+						oscillatorNextAmp[parCnt] = 1;
+				freqFixedDeltas[parIndex] =
+						partials->partialFreqDelta[parIndex][localHop + loopDir]
+								* loopDir / overSampling;
+				ampFixedDeltas[parIndex] =
+						partials->partialAmpDelta[parIndex][localHop + loopDir]
+								* loopDir / overSampling;
+			}
+		} else {
+			if (localHop != partials->partialNumFrames[parIndex] - 1) {
+				oscillatorPhases[parCnt] =
+						phaseCopies[indicesMapping[parIndex]];
+				oscillatorNextNormFreq[parCnt] =
+						nextNormFreqCopies[indicesMapping[parIndex]];
+				oscillatorNextAmp[parCnt] =
+						nextAmpCopies[indicesMapping[parIndex]];
+			} else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available
+			{
+				oscillatorPhases[parCnt] = 0;
+				//TODO add freqmove dependency
+				oscillatorNextNormFreq[parCnt] =
+						partials->partialFrequencies[parIndex][localHop]
+								* frequencyScaler * prevPitchMultiplier;
+				parDamp = calculateParDamping(parIndex, prevHopNumTh,
+						prevAdsrVal, oscillatorNextNormFreq[parCnt],
+						prevFilterNum, prevFilterFreqs, prevFilterQ);
+				oscillatorNextAmp[parCnt] =
+						partials->partialAmplitudes[parIndex][localHop]
+								* parDamp;
+				if(oscillatorNextAmp[parCnt] > 1)
+						oscillatorNextAmp[parCnt] = 1;
+				freqFixedDeltas[parIndex] =
+						partials->partialFreqDelta[parIndex][localHop + loopDir]
+								* loopDir / overSampling;
+				ampFixedDeltas[parIndex] =
+						partials->partialAmpDelta[parIndex][localHop + loopDir]
+								* loopDir / overSampling;
+			}
+		}
+		// remove aliasing, skipping partial over nyquist freq
+		if (oscillatorNextNormFreq[parCnt] > nyqNorm) {
+			//cout << nyqNorm << endl;
+			nyquistCut[parIndex] = true;
+			continue;
+		}
+		nyquistCut[parIndex] = false;
+
+		// first set up freq, cos filter affects amplitude damping according to freq content
+		oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts
+		// save next values, current for next round
+		oscillatorNextNormFreq[parCnt] = (freqMovement
+				* (partials->partialFrequencies[parIndex][localHop + loopDir]
+						- freqFixedDeltas[parIndex] * steps * loopDirShift)
+				* frequencyScaler
+				+ (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
+				* pitchMultiplier;
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
+				- oscillatorNormFrequencies[parCnt]) / hopCounter;
+		// this second weird passage handles dissonance control, morphing between regular and mean frequencies
+		oscillatorNormFreqDerivatives[parCnt] = freqMovement
+				* oscillatorNormFreqDerivatives[parCnt]
+				+ (1 - freqMovement)
+						* ((oscStatNormFrequenciesMean[parIndex]
+								* pitchMultiplier)
+								- oscillatorNormFrequencies[parCnt])
+						/ hopCounter;
+
+		parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
+				oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
+
+		// now amplitudes
+		oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts
+		// save next values, current for next round
+		//delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop];
+		oscillatorNextAmp[parCnt] =
+				(partials->partialAmplitudes[parIndex][localHop + loopDir]
+						- (ampFixedDeltas[parIndex]) * steps * loopDirShift)
+						* parDamp;
+		if(oscillatorNextAmp[parCnt] > 1)
+			oscillatorNextAmp[parCnt] = 1;
+
+		// to avoid bursts when transients are played backwards
+		if ((loopDir == -1) && (localHop - 1 == 0) && (overSampling == 1)) {
+			oscillatorNextAmp[parCnt] = 0;
+		}
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
+				- oscillatorAmplitudes[parCnt]) / hopCounter;
+
+		// if next is not going to loop boundaries, get next deltas [same direction]
+		if ((((currentPartialHop + loopDir) * overSampling != loopEndHop)
+				|| (loopDir == -1))
+				&& (((currentPartialHop + loopDir) * overSampling + loopDir
+						!= loopStartHop) || (loopDir == 1))) {
+			freqFixedDeltas[parIndex] =
+					partials->partialFreqDelta[parIndex][localHop + loopDir]
+							* loopDir / overSampling;
+			ampFixedDeltas[parIndex] =
+					partials->partialAmpDelta[parIndex][localHop + loopDir]
+							* loopDir / overSampling;
+		} else // .. otherwise, keep deltas but change sign [co swe change direction]
+		{
+			freqFixedDeltas[parIndex] = -freqFixedDeltas[parIndex];
+			ampFixedDeltas[parIndex] = -ampFixedDeltas[parIndex];
+		}
+
+		// finally update current mapping between oscillators and partials
+		indicesMapping[parIndex] = parCnt;
+		parCnt++;
+	}
+	actPartNum = parCnt;
+	// [NEON] if not multiple of 4...
+	if (actPartNum % 4 != 0)
+		addFakeOsc();
+
+	updatePrevControls();
+}
+
+void OscillatorBank::addFakeOsc() {
+	// ...calculate difference
+	int newPartNum = (actPartNum + 3) & ~0x3;
+	// ...add fake oscillators until total num is multiple of 4
+	for (int i = actPartNum; i < newPartNum; i++) {
+		oscillatorAmplitudes[i] = 0;
+		oscillatorNormFrequencies[i] = 0;
+		oscillatorAmplitudeDerivatives[i] = 0;
+		oscillatorNormFreqDerivatives[i] = 0;
+		oscillatorPhases[i] = 0;
+	}
+	// ...and update num of active partials
+	actPartNum = newPartNum;
+}
+
+void OscillatorBank::play(float vel) {
+	// set attack and release params according to velocity
+	//adsr.setAttackRate((minAttackTime + ((1 - vel) * deltaAttackTime)) * rate);
+	adsr.setAttackRate(minAttackTime * rate);
+	//adsr.setReleaseRate((minReleaseTime + (1 - vel) * deltaReleaseTime) * rate);
+	adsr.setReleaseRate(minReleaseTime * rate);
+
+	// set timbre
+	hopNumTh = log((1 - vel) + 1) / log(2) * 20000;
+
+	state = bank_toreset;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+// private methods
+//---------------------------------------------------------------------------------------------------------------------------
+
+bool OscillatorBank::loader(char *filename, int hopsize, int samplerate) {
+	rate = samplerate;
+	loaded = parser.parseFile(filename, hopsize, samplerate);
+	return loaded;
+}
+
+int OscillatorBank::jumpToHop() {
+	int jumpGap = abs(jumpHop - currentHop / overSampling); // gaps in partial reference
+
+	// can't jump to self dude
+	if (jumpGap == 0)
+		return 1;
+
+	// direction is in general maintained with jump
+	if (jumpHop == 0)
+		setDirection(1);
+	else if (jumpHop == lastHop)
+		setDirection(-1);
+
+	dbox_printf("\tJump from %d to %d\n", currentHop / overSampling, jumpHop);
+	dbox_printf("\tdirection %d\n", loopDir);
+
+	currentHop = jumpHop * overSampling;
+
+	if (nextEnvState() != 0)
+		return 0; // release has ended!
+
+	checkSpeed();
+
+	int parIndex, localHop, targetHop;
+	float parDamp = 1;
+	int currentPartialHop = currentHop / overSampling;
+	int targetPartialHop = jumpHop;
+
+	actPartNum = partials->activePartialNum[currentPartialHop];
+	actPart = partials->activePartials[currentPartialHop];
+	int targetActParNum = partials->activePartialNum[targetPartialHop];
+	unsigned int *targetActPar = partials->activePartials[targetPartialHop];
+
+	envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release]
+
+	int parCnt = 0;
+	int currentHopReminder = currentHop % overSampling;
+
+	// steps to walk where i am [bank of partial hop] from previous partial hop
+	int steps = currentHopReminder * (overSampling != 1); // no oversampling 0, oversampling and going ff currentHopReminder
+
+	for (int i = 0; i < actPartNum; i++) {
+		// find partial and frame
+		parIndex = actPart[i];
+		//localHop	= partials->localPartialFrames[currentPartialHop][parIndex];
+		localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
+
+		// if this partial was over nyquist on previous hop...
+		if (nyquistCut[parIndex]) {
+			// ...restart from safe values
+			oscillatorPhases[parCnt] = 0;
+			//TODO add freqmove dependency
+			oscillatorNextNormFreq[parCnt] =
+					(partials->partialFrequencies[parIndex][localHop]
+							+ freqFixedDeltas[parIndex] * steps * loopDir)
+							* frequencyScaler * prevPitchMultiplier;
+			oscillatorNextAmp[parCnt] = 0;
+		} else if (loopDir == 1) {// otherwise recover phase, target freq and target amp from previous frame
+			if ((localHop != 0)
+					|| ((overSampling > 1) && (currentHopReminder != 0))) {
+				oscillatorPhases[parCnt] =
+						phaseCopies[indicesMapping[parIndex]];
+				oscillatorNextNormFreq[parCnt] =
+						nextNormFreqCopies[indicesMapping[parIndex]];
+				oscillatorNextAmp[parCnt] =
+						nextAmpCopies[indicesMapping[parIndex]];
+			} else { // first oscillator hop [both for bank and partial], so no previous data are available
+				oscillatorPhases[parCnt] = 0;
+				//TODO add freqmove dependency
+				oscillatorNextNormFreq[parCnt] =
+						partials->partialFrequencies[parIndex][localHop]
+								* frequencyScaler * prevPitchMultiplier;
+				parDamp = calculateParDamping(parIndex, prevHopNumTh,
+						prevAdsrVal, oscillatorNextNormFreq[parCnt],
+						prevFilterNum, prevFilterFreqs, prevFilterQ);
+				oscillatorNextAmp[parCnt] =
+						partials->partialAmplitudes[parIndex][localHop]
+								* parDamp;
+				if(oscillatorNextAmp[parCnt] > 1)
+						oscillatorNextAmp[parCnt] = 1;
+			}
+		} else {
+			if (( (unsigned)localHop != partials->partialNumFrames[parIndex] - 1)
+					|| ((overSampling > 1) && (currentHopReminder != 0))) {
+				oscillatorPhases[parCnt] =
+						phaseCopies[indicesMapping[parIndex]];
+				oscillatorNextNormFreq[parCnt] =
+						nextNormFreqCopies[indicesMapping[parIndex]];
+				oscillatorNextAmp[parCnt] =
+						nextAmpCopies[indicesMapping[parIndex]];
+			} else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available, so retrieve where i am
+			{
+				oscillatorPhases[parCnt] = 0;
+				//TODO add freqmove dependency
+				oscillatorNextNormFreq[parCnt] =
+						partials->partialFrequencies[parIndex][localHop]
+								* frequencyScaler * prevPitchMultiplier;
+				parDamp = calculateParDamping(parIndex, prevHopNumTh,
+						prevAdsrVal, oscillatorNextNormFreq[parCnt],
+						prevFilterNum, prevFilterFreqs, prevFilterQ);
+				oscillatorNextAmp[parCnt] =
+						partials->partialAmplitudes[parIndex][localHop]
+								* parDamp;
+				if(oscillatorNextAmp[parCnt] > 1)
+						oscillatorNextAmp[parCnt] = 1;
+			}
+		}
+		// remove aliasing, skipping partial over nyquist freq
+		if (oscillatorNextNormFreq[parCnt] > nyqNorm) {
+			//cout << nyqNorm << endl;
+			nyquistCut[parIndex] = true;
+			continue;
+		}
+		nyquistCut[parIndex] = false;
+
+		// check what happens of this partial at target hop
+		float targetFreqVal, targetAmpVal;
+		//targetHop = partials->localPartialFrames[targetPartialHop][parIndex];
+		targetHop = targetPartialHop - partials->partialStartFrame[parIndex];
+
+		if (targetHop == -1)
+			targetFreqVal = targetAmpVal = 0;
+		else {
+			targetFreqVal = partials->partialFrequencies[parIndex][targetHop]
+					* frequencyScaler; // pitch shift will be multiplied later!!!
+			targetAmpVal = partials->partialFrequencies[parIndex][targetHop]; // parDamp will be multiplied later!!!
+		}
+
+		// first set up freq, cos filter affects amplitude damping according to freq content
+		oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts
+		// save next values, current for next round
+		oscillatorNextNormFreq[parCnt] = (freqMovement * targetFreqVal
+				+ (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
+				* pitchMultiplier;
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
+				- oscillatorNormFrequencies[parCnt]) / hopCounter;
+		// this second weird passage handles dissonance control, morphing between regular and mean frequencies
+		oscillatorNormFreqDerivatives[parCnt] = freqMovement
+				* oscillatorNormFreqDerivatives[parCnt]
+				+ (1 - freqMovement)
+						* ((oscStatNormFrequenciesMean[parIndex]
+								* pitchMultiplier)
+								- oscillatorNormFrequencies[parCnt])
+						/ hopCounter;
+
+		parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
+				oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
+
+		// now amplitudes
+		oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts
+		// save next values, current for next round
+		oscillatorNextAmp[parCnt] = targetAmpVal * parDamp;
+		if(oscillatorNextAmp[parCnt] > 1)
+				oscillatorNextAmp[parCnt] = 1;
+		// to avoid bursts when transients are played backwards
+		if ((loopDir == -1) && (targetHop == 0)
+				&& ((overSampling == 1) || (currentHopReminder == 0))) {
+			oscillatorNextAmp[parCnt] = 0;
+		}
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
+				- oscillatorAmplitudes[parCnt]) / hopCounter;
+
+		//if partial does not die at target, calculate deltas according to direction
+		if (targetHop != -1) {
+			freqFixedDeltas[parIndex] =
+					partials->partialFreqDelta[parIndex][targetHop] * loopDir
+							/ overSampling;
+			ampFixedDeltas[parIndex] =
+					partials->partialAmpDelta[parIndex][targetHop] * loopDir
+							/ overSampling;
+		}
+
+		// finally update current mapping between oscillators and partials
+		indicesMapping[parIndex] = parCnt;
+		parCnt++;
+	}
+	actPartNum = parCnt;
+
+	// now add the ones that start at target hop!
+	for (int i = 0; i < targetActParNum; i++) {
+		// find partial and frame
+		parIndex = targetActPar[i];
+		//targetHop	= partials->localPartialFrames[targetPartialHop][parIndex];
+		targetHop = targetPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
+
+		// check if this partials was already active before the jump
+		//localHop = partials->localPartialFrames[currentPartialHop][parIndex];
+		localHop = currentPartialHop - partials->partialStartFrame[parIndex];
+
+		// if yes, skip it
+		if (localHop != -1)
+			continue;
+
+		// otherwise add it to active bunch and calcucalte values
+
+		// first set up freq, cos filter affects amplitude damping according to freq content
+		oscillatorNormFrequencies[parCnt] = 0;
+		// save next values, current for next round
+		oscillatorNextNormFreq[parCnt] = (freqMovement
+				* partials->partialFrequencies[parIndex][targetHop]
+				* frequencyScaler
+				+ (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
+				* pitchMultiplier;
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
+				- oscillatorNormFrequencies[parCnt]) / hopCounter;
+		// this second weird passage handles dissonance control, morphing between regular and mean frequencies
+		oscillatorNormFreqDerivatives[parCnt] = freqMovement
+				* oscillatorNormFreqDerivatives[parCnt]
+				+ (1 - freqMovement)
+						* ((oscStatNormFrequenciesMean[parIndex]
+								* pitchMultiplier)
+								- oscillatorNormFrequencies[parCnt])
+						/ hopCounter;
+
+		parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
+				oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
+
+		// now amplitudes
+		oscillatorAmplitudes[parCnt] = 0;
+		// save next values, current for next round
+		oscillatorNextAmp[parCnt] =
+				partials->partialFrequencies[parIndex][targetHop] * parDamp;
+		if(oscillatorNextAmp[parCnt] > 1)
+				oscillatorNextAmp[parCnt] = 1;
+		// derivatives are (next hop value*next damping) - (current hop value*current damping)  ---> next hop must be available, in both directions, because of control on active partials
+		oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
+				- oscillatorAmplitudes[parCnt]) / hopCounter;
+
+		//calculate deltas according to direction
+		freqFixedDeltas[parIndex] =
+				partials->partialFreqDelta[parIndex][targetHop] * loopDir
+						/ overSampling;
+		ampFixedDeltas[parIndex] =
+				partials->partialAmpDelta[parIndex][targetHop] * loopDir
+						/ overSampling;
+
+		// finally update current mapping between oscillators and partials
+		indicesMapping[parIndex] = parCnt;
+		parCnt++;
+
+	}
+	// [NEON] if not multiple of 4...
+	if (actPartNum % 4 != 0)
+		addFakeOsc();
+
+	updatePrevControls();
+
+	jumpHop = -1;
+
+	return 0;
+}
+
+int OscillatorBank::nextEnvState() {
+	/*
+	 envState = Attack.getState();	// to determine what state we are in [attack, decay, sustain, release]
+
+	 // osc bank is playing the tail and the tail ends...
+	 if( (state == bank_playing)&&(envState == env_idle) )
+	 {
+	 state = bank_stopped;	// ...stop bank
+	 return 1;					// and return immediately
+	 }
+	 else if( (envState == env_attack) || (envState == env_decay) )
+	 {
+	 // run envelopes until next frame
+	 dampWeight	= Attack.process(hopSize);
+	 }
+	 else if(envState == env_release)
+	 {
+	 // run envelopes until next frame
+	 dampWeight 	= Attack.process(hopSize);
+	 releaseDamp = Release.process(hopSize);
+	 }*/
+
+	envState = adsr.getState();
+	// osc bank is playing the tail and the tail ends...
+	if ((state == bank_playing) && (envState == env_idle)) {
+		state = bank_stopped; // ...stop bank
+		adsrVal = 0;
+		return 1; // and return immediately
+	} else
+		adsrVal = adsr.process(hopSize);
+
+	return 0;
+}
+
+void OscillatorBank::checkDirection() {
+	// end of the loop or end of file
+	if (((currentHop >= loopEndHop) && (loopDir == 1))
+			|| ((currentHop >= lastHop) && (loopDir == 1))) {
+		// move backwards
+		setDirection(-1);
+		//dbox_printf("backward from %d\n", loopEndHop);
+	} else if (((currentHop <= loopStartHop) && (loopDir == -1))
+			|| ((currentHop <= 0) && (loopDir == -1))) // start of the loop or start of file
+			{
+		// move forward
+		setDirection(1);
+		//dbox_printf("forward from %d\n", loopStartHop);
+	}
+}
+
+void OscillatorBank::checkSpeed() {
+	// speed control [alike on highways, LOL]
+	if (nextSpeed > 0) {
+		nextSpeed = (nextSpeed < maxSpeed) ? nextSpeed : maxSpeed;
+		nextSpeed = (nextSpeed > minSpeed) ? nextSpeed : minSpeed;
+		speed = nextSpeed;
+		nextSpeed = -1;
+	}
+	hopCounter = hopSize / speed;
+}
+
+int OscillatorBank::checkJump() {
+	//check if has to jump somewhere
+	if (jumpHop > -1) {
+		// needs to jump!
+		if (jumpToHop() == 0)
+			return 0;
+	}
+	return 1; // no jump
+}
+
+bool OscillatorBank::checkOversampling() {
+	//TODO fix this, but need andrew to fix oversampling multiple of period size
+	// if partialsHopSize is not a multiple of oversampling, change hop size to periodically match next partial hop
+	if (hopSizeReminder > 0) {
+		// if next osc bank hop overtakes next partial hop...
+		if ((currentHop + loopDir) * hopSize > partialsHopSize) {
+			hopSize = hopSizeReminder; // ...shrink osc bank hop size to match partial hop
+			return true; // and set next hop as matching with next partial hop
+		}
+	} else if (((currentHop + (1 - loopDirShift)) % overSampling) == 0) // if next osc bank hop matches next partial hop
+		return true; // ...mark next hop as partial hop
+
+	return false; // ,otherwise mark next hop as osc bank hop
+}
+
+void OscillatorBank::updatePrevControls() {
+	prevAdsrVal = adsrVal;
+	prevAmpTh = ampTh;
+	prevHopNumTh = hopNumTh;
+	prevPitchMultiplier = pitchMultiplier;
+	prevFreqMovement = freqMovement;
+	prevFilterNum = filterNum;
+	memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float));
+	memcpy(prevFilterQ, filterQ, filterNum * sizeof(float));
+}
+
+float OscillatorBank::calculateParDamping(int parIndex, int hopNTh,
+		float adsrVl, float nextFreq, int filNum, float *filFreq, float *filQ) {
+	float parDamp = 1;
+
+	// timbre
+	parDamp = ((float) (oscStatNumHops[parIndex] + 1)) / (hopNTh + 1);
+	parDamp = (parDamp > 1) ? 1 : parDamp;
+	parDamp = adsrVl * parDamp;
+
+	//filters
+
+	float filterWeights[MAX_TOUCHES];
+	float filterDamp[MAX_TOUCHES];
+	float filDist;
+	float filterWeightsAcc;
+	float filDmp;
+	float filAmp;
+
+// 		band reject notch filter
+//		float dist, dmp;
+//		for(int k=0; k<filterNum; k++)
+//		{
+//			dist = fabs(oscillatorNextNormFreq[parCnt]-filterFreqs[k]);
+//			if(dist<=filterQ[k])
+//			{
+//				dmp 	= dist/filterQ[k];
+//				parDamp *= dmp*dmp*dmp;
+//			}
+//		}
+
+
+	// each filter is a band pass notch filter
+
+	// if at least one is active
+	if (filNum > 0) {
+		// reset values
+		filDist = 0;
+		filterWeightsAcc = 0;
+		filDmp = 0;
+		filAmp = 0;
+		// for each filter
+		for (int k = 0; k < filNum; k++) {
+			// here are a couple of kludges to boost sound output of hi freq filters
+
+			// damping effect of filter increases with distance, but decreases with filter frequency [kludge]
+			float mul = ((filterMaxF-nextFreq)/filterMaxF) * 0.9 + 0.1 ;
+			//filDist = fabs(nextFreq - filFreq[k])*( ((exp(a*4)-1)/EXP_DENOM) * 0.9 + 0.1 );
+			filDist = fabs(nextFreq - filFreq[k])*mul;
+
+			// these to merge all filters contributions according to distance
+			filterWeights[k] = filterMaxF - filDist;
+			filterWeightsAcc += filterWeights[k];
+			// freqs very close to filter center are slightly amplified
+			// the size of this amp area and the effect of amplification increase with frequency [kludge]
+			if (filDist
+					< filterAmpMinF
+							+ (filterAmpMaxF*(1-mul) - filterAmpMinF) * (1 - filQ[k]) )
+				filAmp = filQ[k] * filterAmpMul*(1-mul);
+			else
+				filAmp = 0;
+			// actual damping
+			filDmp = 1 / (filDist * filQ[k]);
+			filDmp = (filDmp > 1) ? 1 : filDmp;
+			// sum damp+amplification
+			filterDamp[k] = filDmp + filAmp;
+		}
+		// do weighted mean to merge all filters contributions
+		filDmp = 0;
+		for (int k = 0; k < filNum; k++)
+			filDmp += filterDamp[k] * filterWeights[k];
+		filDmp /= filterWeightsAcc;
+		// apply
+		parDamp *= filDmp;
+	}
+
+
+	return parDamp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/OscillatorBank.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,240 @@
+/*
+ * OscillatorBank.h
+ *
+ *  Created on: May 23, 2014
+ *      Author: Victor Zappi and Andrew McPherson
+ */
+
+#ifndef OSCILLATORBANK_H_
+#define OSCILLATORBANK_H_
+
+
+#include <string>
+
+#include "spear_parser.h"
+#include "ADSR.h"
+#include "config.h"
+
+using namespace std;
+
+enum OscBankstates {bank_stopped, bank_playing, bank_toreset};
+
+class OscillatorBank
+{
+public:
+	OscillatorBank();
+	OscillatorBank(string filename, int hopsize=-1, int samplerate=44100);
+	OscillatorBank(char *filename, int hopsize=-1, int samplerate=44100);
+	~OscillatorBank();
+	float *oscillatorPhases;
+	float *oscillatorNormFrequencies;
+	float *oscillatorNormFreqDerivatives;
+	float *oscillatorAmplitudes;
+	float *oscillatorAmplitudeDerivatives;
+	float *oscStatNormFrequenciesMean;
+	float *oscStatNumHops;
+	OscBankstates state;
+	bool note;
+	int actPartNum;
+	unsigned int *actPart;
+	int hopCounter;
+	int lookupTableSize;
+	float *lookupTable;
+	float ampTh;
+	int hopNumTh;
+	float pitchMultiplier;
+	float freqMovement;
+	int filterNum;
+	float filterFreqs[5];
+	float filterQ[5];
+	float filterMaxF;
+	float filterAmpMinF;
+	float filterAmpMaxF;
+	float filterAmpMul;
+
+	bool loadFile(string filename, int hopsize=-1, int samplerate=44100);
+	bool loadFile(char *filename, int hopsize=-1, int samplerate=44100);
+	bool initBank(int oversamp=1);
+	void resetOscillators();
+	int getHopSize() { return hopSize; }
+	void nextHop();
+	void setLoopHops(int start, int end);
+	void play(float vel);
+	void stop();
+	void afterTouch(float vel);
+	int getEnvelopeState();
+	float getFrequencyScaler();
+	void setSpeed(float sp);
+	float getSpeed();
+	float getMaxSpeed();
+	float getMinSpeed();
+	void setJumpHop(int hop);
+	int getLastHop();
+	int getCurrentHop() { return currentHop; }
+
+private:
+
+	bool loaded;
+	int numOfPartials;
+	int numOfOscillators;
+	int partialsHopSize;
+	int overSampling;
+	int hopSize;
+	int hopSizeReminder;
+	int oscBankHopSize;
+	float frequencyScaler;
+	float nyqNorm;
+	int lastHop;
+	int currentHop;
+	int	loopDir;
+	int loopDirShift;
+	int loopStartHop;
+	int loopEndHop;
+	int *indicesMapping;
+	float *phaseCopies;
+	float *oscillatorNextNormFreq;
+	float *oscillatorNextAmp;
+	float *nextNormFreqCopies;
+	float *nextAmpCopies;
+	float *freqFixedDeltas;
+	float *ampFixedDeltas;
+	bool *nyquistCut;
+	Spear_parser parser;
+	Partials *partials;
+	ADSR adsr;
+	float minAttackTime;
+	float deltaAttackTime;
+	float minReleaseTime;
+	float deltaReleaseTime;
+	int envState;
+	int rate;
+	float speed;
+	float nextSpeed;
+	float maxSpeed;
+	float minSpeed;
+	int jumpHop;
+	float adsrVal;
+	float prevAdsrVal;
+	float prevAmpTh;
+	int prevHopNumTh;
+	float prevPitchMultiplier;
+	float prevFreqMovement;
+	int prevFilterNum;
+	float prevFilterFreqs[5];
+	float prevFilterQ[5];
+
+	bool loader(char *filename, int hopsize=-1, int samplerate=44100);
+	void addFakeOsc();
+	void nextOscBankHop();
+	void nextPartialHop();
+	int jumpToHop();
+	void setDirection(int dir);
+	int nextEnvState();
+	void checkDirection();
+	void checkSpeed();
+	int checkJump();
+	bool checkOversampling();
+	void updatePrevControls();
+	float calculateParDamping(int parIndex, int hopNTh, float adsrVl, float nextFreq,
+							  int filNum, float *filFreq, float *filQ);
+};
+
+inline bool OscillatorBank::loadFile(string filename, int hopsize, int samplerate)
+{
+	return loader((char *)filename.c_str(), hopsize, samplerate);
+}
+
+inline bool OscillatorBank::loadFile(char *filename, int hopsize, int samplerate)
+{
+	return loader(filename, hopsize, samplerate);
+}
+
+inline void OscillatorBank::setLoopHops(int start, int end)
+{
+	if(start > end)
+		end = start;
+
+	if(start<0)
+		start = 0;
+	else if(start>lastHop)
+		start = 0;
+	if(end < 1)
+		end = 1;
+	end = (end<=lastHop) ? end : lastHop;
+
+	// set it, take into consideration hop oversampling
+	loopStartHop = start*overSampling;
+	loopEndHop	 = end*overSampling;
+}
+
+inline void OscillatorBank::stop()
+{
+	note = false;
+	adsr.gate(0);
+}
+
+inline float OscillatorBank::getFrequencyScaler()
+{
+	return frequencyScaler;
+}
+
+inline void OscillatorBank::afterTouch(float vel)
+{
+	hopNumTh = log((1-vel)+1)/log(2)*20000;
+	if(adsr.getState()==env_attack)
+		adsr.setAttackRate( (minAttackTime + ( (1-vel)*deltaAttackTime )) * rate );
+	adsr.setReleaseRate( (minReleaseTime+(1-vel)*deltaReleaseTime)* rate );
+}
+
+inline int OscillatorBank::getEnvelopeState()
+{
+	return envState;
+}
+
+inline void OscillatorBank::setSpeed(float sp)
+{
+	nextSpeed = sp;
+}
+
+inline float OscillatorBank::getSpeed()
+{
+	return speed;
+}
+
+inline float OscillatorBank::getMaxSpeed()
+{
+	return maxSpeed;
+}
+
+inline float OscillatorBank::getMinSpeed()
+{
+	return minSpeed;
+}
+
+inline void OscillatorBank::setJumpHop(int hop)
+{
+	if(hop<0)
+		return;
+	hop = (hop<=lastHop) ? hop : lastHop;
+	jumpHop = hop;
+}
+
+inline void OscillatorBank::setDirection(int dir)
+{
+	if(dir>=0)
+	{
+		loopDir			= 1;
+		loopDirShift	= 0;
+	}
+	else
+	{
+		loopDir			= -1;
+		loopDirShift	= 1;
+	}
+}
+
+inline int OscillatorBank::getLastHop()
+{
+	return lastHop;
+}
+#endif /* OSCILLATORBANK_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/PinkNoise.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,16 @@
+/*
+ * PinkNoise.cpp
+ *
+ *  Created on: Oct 15, 2013
+ *      Author: Victor Zappi
+ */
+
+#include "PinkNoise.h"
+
+// miserable definition to init static const array members...otherwise gets error when PinkNoise.h is included into another header file
+const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P)
+const float PinkNoise::P[] = { 0.3190,  0.7756,  0.9613  };
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/PinkNoise.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,49 @@
+#ifndef _PinkNoise_H
+#define _PinkNoise_H
+
+// Technique by Larry "RidgeRat" Trammell 3/2006
+// http://home.earthlink.net/~ltrammell/tech/pinkalg.htm
+// implementation and optimization by David Lowenfels
+
+#include <cstdlib>
+#include <ctime>
+#include <stdlib.h>
+
+#define PINK_NOISE_NUM_STAGES 3
+
+class PinkNoise {
+public:
+  PinkNoise() {
+  srand ( time(NULL) ); // initialize random generator
+    clear();
+  }
+
+  void clear() {
+    for( size_t i=0; i< PINK_NOISE_NUM_STAGES; i++ )
+      state[ i ] = 0.0;
+    }
+
+  float tick() {
+    static const float RMI2 = 2.0 / float(RAND_MAX); // + 1.0; // change for range [0,1)
+    static const float offset = A[0] + A[1] + A[2];
+
+  // unrolled loop
+    float temp = float( rand() );
+    state[0] = P[0] * (state[0] - temp) + temp;
+    temp = float( rand() );
+    state[1] = P[1] * (state[1] - temp) + temp;
+    temp = float( rand() );
+    state[2] = P[2] * (state[2] - temp) + temp;
+    return ( A[0]*state[0] + A[1]*state[1] + A[2]*state[2] )*RMI2 - offset;
+  }
+
+protected:
+  float state[ PINK_NOISE_NUM_STAGES ];
+  static const float A[ PINK_NOISE_NUM_STAGES ];
+  static const float P[ PINK_NOISE_NUM_STAGES ];
+};
+
+//const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P)
+//const float PinkNoise::P[] = { 0.3190,  0.7756,  0.9613  };
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/StatusLED.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,90 @@
+/*
+ * StatusLED.cpp
+ *
+ * Routines for manipulating the status LED
+ *
+ * (c) 2014 Andrew McPherson and Victor Zappi
+ * QMUL, Centre for Digital Music
+ */
+
+#include <iostream>
+#include "StatusLED.h"
+#include "../../include/GPIOcontrol.h"
+
+extern int gShouldStop;
+extern int gVerbose;
+
+using namespace std;
+
+StatusLED::StatusLED() {
+	gpio_number = -1;
+	milliseconds_on = 0;
+	milliseconds_off = 100;
+	blink_thread = -1;
+}
+
+StatusLED::~StatusLED() {
+	if(gpio_number >= 0) {
+		this_should_stop = true;
+		pthread_join(blink_thread, NULL);
+		gpio_unexport(gpio_number);
+	}
+}
+
+bool StatusLED::init(int gpio_pin) {
+	gpio_number = gpio_pin;
+	this_should_stop = false;
+
+	if(gpio_export(gpio_number)) {
+		if(gVerbose)
+			cout << "Warning: couldn't export status LED pin\n";
+	}
+	if(gpio_set_dir(gpio_number, OUTPUT_PIN)) {
+		if(gVerbose)
+			cout << "Couldn't set direction on status LED pin\n";
+		return false;
+	}
+	if(gpio_set_value(gpio_number, LOW)) {
+		if(gVerbose)
+			cout << "Couldn't set value on status LED pin\n";
+		return false;
+	}
+
+
+	if ( pthread_create(&blink_thread, NULL, static_blink_loop, this) )
+	{
+		cout << "Error:unable to create status LED thread" << endl;
+		return false;
+	}
+
+	return true;
+}
+
+void StatusLED::on() {
+	milliseconds_on = 100;
+	milliseconds_off = 0;
+}
+
+void StatusLED::off() {
+	milliseconds_on = 0;
+	milliseconds_off = 100;
+}
+
+void StatusLED::blink(int ms_on, int ms_off) {
+	milliseconds_on = ms_on;
+	milliseconds_off = ms_off;
+}
+
+void* StatusLED::blink_loop(void *) {
+	while(!gShouldStop && !this_should_stop) {
+		if(milliseconds_on != 0)
+			gpio_set_value(gpio_number, HIGH);
+		usleep(1000 * milliseconds_on);
+		if(gShouldStop)
+			break;
+		if(milliseconds_off != 0)
+			gpio_set_value(gpio_number, LOW);
+		usleep(1000 * milliseconds_off);
+	}
+	pthread_exit(NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/StatusLED.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,38 @@
+/*
+ * StatusLED.h
+ *
+ *
+ */
+
+#ifndef STATUSLED_H_
+#define STATUSLED_H_
+
+#include <pthread.h>
+
+class StatusLED
+{
+public:
+	StatusLED();
+	~StatusLED();
+
+	bool init(int gpio_pin);
+
+	void on();
+	void off();
+	void blink(int ms_on, int ms_off);
+
+	static void *static_blink_loop(void *data) {
+		((StatusLED*)data)->blink_loop(NULL);
+		return 0;
+	}
+
+	void* blink_loop(void *);
+
+private:
+	int gpio_number;
+	int milliseconds_on, milliseconds_off;
+	bool this_should_stop;
+	pthread_t blink_thread;
+};
+
+#endif // STATUSLED_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/audio_routines.S	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,185 @@
+@
+@ audio_routines.S
+@
+@ NEON-based functions for time-critical audio processing
+@
+@ Andrew McPherson 2014
+@ Queen Mary University of London
+@
+
+	.syntax unified
+	.arch armv7-a
+	.fpu neon
+
+@ 	void oscillator_bank_neon(int numAudioFrames, float *audioOut,
+@							  int activePartialNum, int lookupTableSize,
+@							  float *phases, float *frequencies, float *amplitudes,
+@							  float *freqDerivatives, float *ampDerivatives,
+@							  float *lookupTable);
+
+@ Registers:
+@    r0: numAudioFrames        How many frames to render
+@    r1: audioOut              Buffer for audio output samples [stereo]
+@    r2: activePartialNum      How many active partials to render
+@    r3: lookupTableSize       Size of lookup table
+@    ---- other arguments start on the stack and are moved: -----
+@    r4: phases                Phase of each oscillator (pointer)
+@    r5: frequencies           Normalised frequency of each oscillator (pointer)
+@    r6: amplitudes            Normalised amplitude of each oscillator (pointer)
+@    r7: freqDerivatives       Derivative of frequency for each oscillator (pointer)
+@    r8: ampDerivatives        Derivative of amplitude for each oscillator (pointer)
+@    r9: lookupTable           Lookup table containing one oscillation
+@
+@ Alignment requirements:
+@    audioOut: 8-byte boundary
+@    phases: 16-byte boundary
+@    frequencies: 16-byte boundary
+@    amplitudes: 16-byte boundary
+@    freqDerivatives: 16-byte bounary
+@    ampDerivatives: 16-byte boundary
+@    lookupTable: 4-byte boundary (TODO: check this)
+
+	.align	2
+	.global	oscillator_bank_neon
+	.thumb
+	.thumb_func
+	.type	oscillator_bank_neon, %function
+oscillator_bank_neon:
+
+
+dSample		.dn		D6.F32
+qPhases		.qn		Q8.F32
+dPhases_0	.dn		D16.F32
+dPhases_1	.dn		D17.F32
+qFreqs		.qn		Q9.F32
+dFreqs_0	.dn		D18.F32
+dFreqs_1	.dn		D19.F32
+qAmps		.qn		Q10.F32
+dAmps_0		.dn		D20.F32
+dAmps_1		.dn		D21.F32
+qFreqDs		.qn		Q11.F32
+dFreqDs_0	.dn		D22.F32
+dFreqDs_1	.dn		D23.F32
+qAmpDs		.qn		Q12.F32
+dAmpDs_0	.dn		D24.F32
+dAmpDs_1	.dn		D25.F32
+
+qBaseInts	.qn		Q13.U32		@ Base indexes: unsigned ints x4
+dBaseInts_0	.dn		D26.U32
+dBaseInts_1	.dn		D27.U32
+qFractions  .qn     Q14.F32		@ Fraction indexes: floats x4
+qTableBase	.qn		Q15.U32		@ Base of lookup table
+
+	cmp r0, #0					@ Check for trivial case 1: zero frames
+	it eq
+	bxeq lr						@ Return if that's the case (otherwise might have odd behaviour)
+	cmp r2, #4					@ Check for trivial case 2: zero oscillators
+	it lt
+	bxlt lr						@ Return if that's the case
+
+	push {r4-r11}				@ Now arguments start 32 bytes above SP
+    add r11, sp, #32			@ Pointer to 32 bytes into the stack
+    ldm r11, {r4-r9}			@ Load 6 arguments into registers
+
+	vdup qTableBase, r9			@ Move lookup table base index into 4 ints
+
+	@ Outer loop: iterate over the number of oscillators, choosing 4 at a
+	@ time to work with.
+oscbank_oscillator_loop:
+	vld1 {dPhases_0, dPhases_1}, [r4]		@ no increment; will store at end of sample loop
+	vld1 {dFreqs_0, dFreqs_1}, [r5]
+	vld1 {dAmps_0, dAmps_1}, [r6]
+	vld1 {dFreqDs_0, dFreqDs_1}, [r7]!		@ increment; won't update at end of sample loop
+	vld1 {dAmpDs_0, dAmpDs_1}, [r8]!
+
+	push {r0-r1,r4-r8}
+	@ --- inner loop: iterate over the number of samples ---
+oscbank_sample_loop:
+	vcvt qBaseInts, qPhases		     		@ Take floor(phases)
+	vmov q2.f32, #1.0						@ Load 1.0 into every slot of q2
+	vshl q0.U32, qBaseInts, #2				@ Shift the indexes left 2 (*4 for float addressing)
+	vcvt qFractions, qBaseInts				@ int back to float
+	vadd q0.U32, q0.U32, qTableBase			@ Find memory addresses
+
+	vmov r4, r5, d0							@ Move two indexes to ARM registers
+	vmov r6, r7, d1							@ Move two more indexes to ARM registers
+	vsub qFractions, qPhases, qFractions	@ fraction = phase - floor(phase)
+
+	vldr.64	d0, [r4]						@ Load two consecutive floats at each location
+	vldr.64 d1, [r5]						@ These hold the previous and following samples in the table
+	vldr.64	d2, [r6]						@ TODO: check whether these work at 4-byte alignment
+	vldr.64 d3, [r7]
+
+	@ Format at this point:
+	@ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after)
+	@ We want:
+	@ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after)
+
+	vuzp.32 q0, q1							@ Now q0 contains before, q1 contains after
+	vsub q2.f32, q2.f32, qFractions			@ q2 = 1.0 - fraction
+	vmul q1.f32, q1.f32, qFractions			@ q1 = fraction * after
+	vmul q0.f32, q0.f32, q2.f32				@ q0 = (1.0 - fraction) * before
+
+	vadd qPhases, qPhases, qFreqs			@ Update phases
+	vadd qFreqs, qFreqs, qFreqDs			@ Update frequencies
+
+	vadd q0.f32, q0.f32, q1.f32				@ Add two interpolated components to get the final sample
+	vdup q2.u32, r3							@ Put lookup table size into each element of q2
+	vcvt qBaseInts, qPhases					@ Take floor of new phases
+	vmul q0.f32, q0.f32, qAmps				@ Multiply samples by current amplitude
+
+	vld1 dSample, [r1]						@ Load the current stereo samples
+	vpadd d2.f32, d0.f32, d1.f32			@ Pairwise accumulate q0 (output sample) into d2
+
+	vand q2, q2, qBaseInts					@ Logical AND of new phase int leaves 1 bit set only if phase >= table size
+	vpadd d3.f32, d2.f32, d2.f32			@ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators
+	vadd qAmps, qAmps, qAmpDs				@ Update amplitudes
+	vcvt q0.f32, q2.u32						@ Convert int back to float after AND operation
+
+	vadd  dSample, dSample, d3.f32			@ Add oscillator outputs to each channel
+
+	subs r0, r0, #1							@ numFrames--
+	vsub qPhases, qPhases, q0.f32			@ Keep phases in table range
+	vst1 dSample, [r1]!						@ Store back in buffer and increment by 8
+
+	it gt
+	bgt oscbank_sample_loop					@ Loop if numFrames > 0
+
+	@ --- end inner loop ---
+	pop {r0-r1,r4-r8}						@ Restore registers: restores audioOut and numFrames, among others
+
+	vst1 {dPhases_0, dPhases_1}, [r4]!		@ Store phases back to array
+	vst1 {dFreqs_0, dFreqs_1}, [r5]!		@ Store frequencies back to array
+	vst1 {dAmps_0, dAmps_1}, [r6]!			@ Store amplitudes back to array
+											@ No need to update r7, r8
+
+	subs r2, r2, #4							@ numPartials -= 4
+	it  gt
+	bgt oscbank_oscillator_loop	@ Loop if numPartials > 0
+
+    pop {r4-r11}
+	bx lr
+
+
+@   void wavetable_interpolate_neon(int numSamplesIn, int numSamplesOut,
+@                              float *tableIn, float *tableOut);
+
+@ Registers:
+@    r0: numSamplesIn          Size of the input table
+@    r1: numSamplesOut         Size of the output table
+@    r2: tableIn               Pointer to input table
+@    r3: tableOut              Pointer to output table
+
+@ Alignment requirements:
+@    tableIn: 8-byte boundary
+@    tableOut: 8-byte boundary
+
+	.align	2
+	.global	wavetable_interpolate_neon
+	.thumb
+	.thumb_func
+	.type	wavetable_interpolate_neon, %function
+wavetable_interpolate_neon:
+    @ TODO
+
+    bx lr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/config.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,46 @@
+/*
+ * config.h
+ *
+ * Global settings for D-Box project
+ *
+ * Andrew McPherson and Victor Zappi 2014
+ */
+
+
+#ifndef DBOX_CONFIG_H_
+#define DBOX_CONFIG_H_
+
+
+/* Number of maximum touches used by the TouchKey sensors */
+#define MAX_TOUCHES 5
+
+// for sensor 1 filter
+#define EXP_DENOM 53.5981500331			// exp(4)-1
+
+/* Define this to use Xenomai real-time extensions */
+#define DBOX_USE_XENOMAI
+//#define OLD_OSCBANK
+
+/* Define this if the new cape is in use (changes pinouts and I2C address) */
+#define DBOX_CAPE
+
+#ifdef DBOX_USE_XENOMAI
+// Xenomai-specific includes
+#include <sys/mman.h>
+
+#include <native/task.h>
+#include <native/timer.h>
+#include <rtdk.h>
+#endif
+
+#ifdef DBOX_USE_XENOMAI
+
+#define dbox_printf rt_printf
+
+#else
+
+#define dbox_printf printf
+
+#endif
+
+#endif /* DBOX_CONFIG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/logger.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,188 @@
+/*
+ * logger.cpp
+ *
+ *  Created on: Aug 6, 2014
+ *      Author: VIctor Zappi and Andrew McPherson
+ */
+
+#include "logger.h"
+
+// main extern vars
+extern bool gShouldStop;
+extern int gVerbose;
+
+// file nanme extern vars
+extern char gId;
+extern char gGroup;
+
+
+// logged extern vars
+extern int s0TouchNum;
+extern float s0Touches_[MAX_TOUCHES];
+extern float s0Size_[MAX_TOUCHES];
+extern int s0LastIndex;
+
+extern int s1TouchNum;
+extern float s1Touches_[MAX_TOUCHES];
+extern float s1Size_[MAX_TOUCHES];
+extern int s1LastIndex;
+
+extern int fsr;
+
+
+
+string logPath			= "/boot/uboot/instrumentLog";
+string logFileIncipit	= "/datalog";
+string logFileName		= "";
+ofstream logFile;
+timeval logTimeVal;
+unsigned long long logTimeOrig;
+int logCnt				= 0;	// counts how many lines so far
+int logCntSwap			= 50;	// how many log lines before closing and re-opening the file
+
+
+// create the log file, using incremental name convention
+int initLogLoop()
+{
+	if(gVerbose==1)
+		cout << "---------------->Init Log Thread" << endl;
+
+
+	// transform chars into strings via stringstream objs
+	stringstream id_ss, group_ss, freedom_ss;
+	id_ss 		<< gId;
+	group_ss 	<< gGroup;
+
+	int logNum	= -1;
+	int logMax	= -1;
+	int pathLen	= logPath.length() + logFileIncipit.length() + 4;	// + 4 is: "_", id, group, "_"
+	glob_t globbuf;
+
+	// check how many log files are already there, and choose name according to this
+	glob( (logPath + logFileIncipit + "*").c_str(), 0, NULL, &globbuf);
+
+	// cycle through all and find the highest index
+	for(unsigned int i=0; i<globbuf.gl_pathc; i++)
+	{
+		// playing with 0-9 char digits, forming a number from 0 to 9999
+		logNum  = (globbuf.gl_pathv[i][pathLen]-48)   * 1000;	// 42 to 45 are the indices of the chars forming the file index
+		logNum += (globbuf.gl_pathv[i][pathLen+1]-48) * 100;
+		logNum += (globbuf.gl_pathv[i][pathLen+2]-48) * 10;
+		logNum +=  globbuf.gl_pathv[i][pathLen+3]-48;
+		if(logNum > logMax)
+			logMax = logNum;
+	}
+	logNum = logMax + 1;	// new index
+
+	globfree(&globbuf);
+
+	ostringstream numString;
+	numString << setw (4) << setfill ('0') << logNum;	// set integer with 4 figures
+
+	// here are the new names: PATH + DIR + INCIPIT + _ + id + group + freedom + _ + NUM (4figures) + _A.txt
+	logFileName	= logPath + logFileIncipit;
+	logFileName	+= "_" + id_ss.str() + group_ss.str() + freedom_ss.str();
+	logFileName	+= "_" + numString.str();	 //static_cast<ostringstream*>( &(ostringstream() << logNum) )->str();
+	logFileName	+= ".txt";
+
+
+	// create new files
+	FILE *fp_a		= fopen(logFileName.c_str(), "wb");
+	if(!fp_a)
+	{
+		dbox_printf("Cannot create files...\n");
+		return 2;
+	}
+	fclose(fp_a);
+
+	// ready to append
+	logFile.open(logFileName.c_str(), ios::out | ios::app);
+
+	dbox_printf("Logging on file %s\n", logFileName.c_str());
+
+	return 0;
+}
+
+
+void writeData(unsigned long long time)
+{
+
+	float fsr_ = ((float)(1799-fsr)/1799.0);
+	logFile << time 				<< "\t"		// timestamp
+			<< s0TouchNum			<< "\t";	// sensor 0 touch count
+	for(int i=0; i<MAX_TOUCHES; i++)
+		logFile << s0Touches_[i] 	<< "\t";	// sensor 0 touch pos x
+	for(int i=0; i<MAX_TOUCHES; i++)
+		logFile << s0Size_[i] 		<< "\t";	// sensor 0 touch size
+	logFile << s0LastIndex 			<< "\t"		// sensor 0 last index
+			<< fsr_					<< "\t"		// sensor 0 FSR pressure
+			<< s1TouchNum			<< "\t";	// sensor 1 touch count
+	for(int i=0; i<MAX_TOUCHES; i++)
+		logFile << s1Touches_[i] 	<< "\t";	// sensor 1 touch pos x
+	for(int i=0; i<MAX_TOUCHES; i++)
+		logFile	<< s1Size_[i] 		<< "\t";	// sensor 1 touch size
+	logFile << s1LastIndex 			<< "\t"		// sensor 1 last index
+	//... AND SO ON
+			<< "\n";
+
+	//dbox_printf("%d\n", s0LastIndex);
+	//dbox_printf("s0TouchNum: %d\t s0Touches[0]: %f\t s0Size[0]: %f\t s0LastIndex: %d\n", s0TouchNum, s0Touches_[0], s0Size_[0], s0LastIndex);
+
+}
+
+void logData(unsigned long long time)
+{
+	// if it's time to change write-file
+	if(logCnt >= logCntSwap)
+	{
+		logFile.close();	// close file, dump stream
+		logCnt = 0;		// ready for another whole round
+
+		// open again, ready to append
+		logFile.open(logFileName.c_str(), ios::out | ios::app);
+	}
+
+	writeData(time);
+
+	logCnt++;
+}
+
+
+
+
+void *logLoop(void *)
+{
+	set_realtime_priority(10);
+
+	if(gVerbose==1)
+		dbox_printf("_________________Log Thread!\n");
+
+	// get time reference
+	gettimeofday(&logTimeVal, NULL);
+	logData(0);
+
+	logTimeOrig = logTimeVal.tv_usec;
+	logTimeOrig *= 0.001;					// from usec to msec
+	logTimeOrig += logTimeVal.tv_sec*1000;	// from sec to msec
+
+	usleep(5000);
+
+	while(!gShouldStop)
+	{
+		gettimeofday(&logTimeVal, NULL);
+		unsigned long long currentTime = logTimeVal.tv_usec;
+		currentTime *= 0.001;					// from usec to msec
+		currentTime += logTimeVal.tv_sec*1000;	// from sec to msec
+
+		logData(currentTime-logTimeOrig);
+
+		usleep(5000);
+	}
+
+	if(logFile!=NULL)
+		logFile.close();
+
+	dbox_printf("log thread ended\n");
+
+	return (void *)0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/logger.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,30 @@
+/*
+ * logger.h
+ *
+ *  Created on: Aug 6, 2014
+ *      Author: Victor Zappi and Andrew McPherson
+ */
+
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#include <string.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <fstream>		// file handle
+#include <iostream>		// stringstream
+#include <sstream>		// stringstream
+#include <glob.h>		// alternative to dirent.h to handle files in dirs
+#include <iomanip>		// setfill
+#include <sys/time.h>	// elapsed time
+
+#include "config.h"
+#include "prio.h"
+
+using namespace std;
+
+int initLogLoop();
+void *logLoop(void *);
+
+
+#endif /* LOGGER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/main.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,490 @@
+/*
+ *  RTAudio.cpp
+ *
+ *  Central control code for hard real-time audio on BeagleBone Black
+ *  using PRU and Xenomai Linux extensions. This code began as part
+ *  of the Hackable Instruments project (EPSRC) at Queen Mary University
+ *  of London, 2013-14.
+ *
+ *  (c) 2014 Victor Zappi and Andrew McPherson
+ *  Queen Mary University of London
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <math.h>
+#include <iostream>
+#include <signal.h>		// interrupt handler
+#include <assert.h>
+#include <vector>
+#include <dirent.h>		// to handle files in dirs
+#include <mntent.h>		// to check if device is mounted
+#include <sys/mount.h>	// mount()
+#include <sys/time.h>	// elapsed time
+#include <NE10.h>		// neon library
+
+// thread priority
+#include <pthread.h>
+#include <sched.h>
+
+// get_opt_long
+#include <getopt.h>
+
+#include "../../include/RTAudio.h"
+#include "config.h"
+#include "sensors.h"
+#include "OscillatorBank.h"
+#include "StatusLED.h"
+#include "logger.h"
+
+using namespace std;
+
+//----------------------------------------
+// main variables
+//----------------------------------------
+vector<OscillatorBank*> gOscBanks;
+int gCurrentOscBank = 0;
+int gNextOscBank = 0;
+int oscBnkOversampling 				 = 1;	// oscillator bank frame oversampling
+
+const int kStatusLEDPin 	 = 30;	// P9-11 controls status LED
+StatusLED gStatusLED;
+
+pthread_t keyboardThread;
+pthread_t logThread;
+
+// general settings
+int gVerbose		= 0;        			// verbose flag
+bool forceKeyboard 	= true;					// activate/deactivate keyboard control
+bool forceSensors	= false;				// activate/deactivate sensor control
+bool forceLog		= true;					// activate/deactivate log on boot partition
+bool useSD   		= true;    				// activate/deactivate file loading from SD [as opposed to emmc]
+bool useAudioTest   = false;    			// activate/deactivate sensors and test audio only
+
+// audio settings
+unsigned int gPeriodSize = 8;				// period size for audio
+char* gPartialFilename = 0;					// name of the partials file to load
+bool gAudioIn = false;						// stereo audio in status
+
+int touchSensor0Address = 0x0C;				// I2C addresses of touch sensors
+int touchSensor1Address = 0x0B;
+bool useNewSensors = false;
+
+char sdPath[256]			= "/dev/mmcblk0p2";			// system path of the SD, partition 2
+char mountPath[256]			= "/root/d-box/usersounds";	// mount point of SD partition 2 [where user files are]
+char gUserDirName[256] 		= "usersounds";				// Directory in which user analysis files can be found [dir of mountPath]
+char gDefaultDirName[256] 	= "sounds";					// Directory in which built in analysis files can be found
+char *gDirName;
+bool gIsLoading 			= false;
+int fileCnt 				= 0;
+std::vector <std::string> files;
+
+char gId	= 'f';	// from 0 to 14, hexadecimal [0-d]! f means not set
+char gGroup	= '2';	// 0 is no info, 1 info.   2 is not set
+
+// audio in filter
+extern ne10_float32_t *filterState[2];
+extern ne10_float32_t *filterIn[2];
+extern ne10_float32_t *filterOut[2];
+
+struct arg_data
+{
+   int  argc;
+   char **argv;
+};
+
+arg_data args;
+
+
+int readFiles()
+{
+	if(useSD)
+		gDirName = gUserDirName;
+	else
+		gDirName = gDefaultDirName;
+	DIR *dir;
+	struct dirent *ent;
+
+	// From http://stackoverflow.com/questions/612097/how-can-i-get-a-list-of-files-in-a-directory-using-c-or-c
+	if ((dir = opendir (gDirName)) != NULL) {
+		/* print all the files and directories within directory */
+		while ((ent = readdir (dir)) != NULL) {
+			// Ignore dotfiles and . and .. paths
+			if(!strncmp(ent->d_name, ".", 1))
+				continue;
+
+			//dbox_printf("%s\n", ent->d_name);
+
+			// take only .dbx and .txt files
+			string name = string(ent->d_name);
+			int len		= name.length();
+
+			bool dboxFile = false;
+
+			if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') )
+				dboxFile = true;
+			if( (name[len-4]=='.') && (name[len-3]=='t') && (name[len-2]=='x') && (name[len-1]=='t') )
+				dboxFile = true;
+
+			if(dboxFile)
+			{
+				fileCnt++;
+				//dbox_printf("%s\n", ent->d_name);
+				files.push_back( std::string( ent->d_name ) );
+			}
+		}
+		closedir (dir);
+	} else {
+		/* could not open directory */
+		printf("Could not open directory %s\n", gDirName);
+		return 1;
+	}
+
+	// order by name
+	std::sort( files.begin(), files.end() );
+
+	if(fileCnt==0)
+	{
+		printf("No .dbx or .txt files in %s!\n", gDirName);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Load sounds from the directory */
+void loadAudioFiles(bool loadFirstFile)
+{
+	char fullFileName[256];
+
+	if(loadFirstFile) {
+		strcpy(fullFileName, gDirName);
+		strcat(fullFileName, "/");
+		strncat(fullFileName, files[0].c_str(), 255 - strlen(gDirName));
+		dbox_printf("Loading first file %s...\n", fullFileName);
+		OscillatorBank *bank = new OscillatorBank(fullFileName);
+		if(bank->initBank(oscBnkOversampling)) {
+			bank->setLoopHops(100, bank->getLastHop());
+			gOscBanks.push_back(bank);
+		}
+	}
+
+	else {
+		for(int i=1; i<fileCnt; i++){
+			strcpy(fullFileName, gDirName);
+			strcat(fullFileName, "/");
+			strncat(fullFileName, files[i].c_str(), 255 - strlen(gDirName));
+			dbox_printf("Loading file %s...\n", fullFileName);
+			OscillatorBank *bank = new OscillatorBank(fullFileName);
+			if(bank->initBank(oscBnkOversampling)) {
+				bank->setLoopHops(100, bank->getLastHop());
+				gOscBanks.push_back(bank);
+			}
+		}
+	}
+}
+
+// adapted from http://program-nix.blogspot.co.uk/2008/08/c-language-check-filesystem-is-mounted.html
+int checkIfMounted (char * dev_path)
+{
+	FILE * mtab				= NULL;
+	struct mntent * part	= NULL;
+	int is_mounted			= 0;
+
+	if ( ( mtab = setmntent ("/etc/mtab", "r") ) != NULL)
+	{
+		while ( ( part = getmntent ( mtab) ) != NULL)
+		{
+			if ( ( part->mnt_fsname != NULL ) && ( strcmp ( part->mnt_fsname, dev_path ) ) == 0 )
+			   is_mounted = 1;
+		}
+	endmntent(mtab);
+	}
+	return is_mounted;
+}
+
+int mountSDuserPartition()
+{
+	if(checkIfMounted(sdPath))
+	{
+		printf("device %s already mounted, fair enough, let's move on\n", sdPath);
+		return 0;
+	}
+	// if mount rootfs from SD [rootfs eMMC not used] or from eMMC via properly formatted SD [SD rootfs used as storage volume]
+	// we always use rootfs on SD as storage volume ----> "/dev/mmcblk0p2"
+	int ret = mount(sdPath, "/root/d-box/usersounds", "vfat",  0, NULL);
+	if (ret!=0)
+	{
+			printf("Error in mount...%s\n", strerror(ret));
+			return 1;
+	}
+	return 0;
+}
+
+int initSoundFiles()
+{
+	if(gVerbose==1)
+		cout << "---------------->Init Audio Thread" << endl;
+
+	if(useSD)
+	{
+		// mount the SD partition where user sounds are located
+		// [this is p2, p1 is already mounted and we will log data there]
+		if(mountSDuserPartition()!=0)
+			return -1;
+	}
+
+	gIsLoading = true;
+
+	// read files from SD and order them alphabetically
+	if(readFiles()!=0)
+		return 1;
+
+	// load first file into oscBank
+	loadAudioFiles(true);
+
+	return 0;
+}
+
+//---------------------------------------------------------------------------------------------------------
+
+// Handle Ctrl-C
+void interrupt_handler(int var)
+{
+	// kill keyboard thread mercilessly
+	if(forceKeyboard)
+		pthread_cancel(keyboardThread);
+
+	gShouldStop = true;
+}
+
+
+void parseArguments(arg_data args)
+{
+	// Default filename;
+	gPartialFilename = strdup("D-Box_sound_250_60_40_h88_2.txt");
+
+	// TODO: complete this
+	struct option long_option[] =
+	{
+		{"help", 0, NULL, 'h'},
+		{"period", 1, NULL, 'p'},
+		{"verbose", 1, NULL, 'v'},
+		{"audioin", 1, NULL, 'i'},
+		{"file", 1, NULL, 'f'},
+		{"keyboard", 1, NULL, 'k'},
+		{"audio-test", 0, NULL, 'A'},
+		{"new-sensors", 0, NULL, 'S'},
+		{"sensor0", 1, NULL, 'Q'},
+		{"sensor1", 1, NULL, 'R'},
+		{"log", 1, NULL, 'l'},
+		{"usesd", 1, NULL, 'u'},
+		{"oversamp", 1, NULL, 'o'},
+		{"boxnumber", 1, NULL, 'n'},
+		{"group", 1, NULL, 'g'},
+		{NULL, 0, NULL, 0},
+	};
+	int morehelp = 0;
+	int tmp = -1;
+
+	while (1)
+	{
+		int c;
+		if ((c = getopt_long(args.argc, args.argv, "hp:vf:ki:sAQ:R:Sl:u:o:n:g:", long_option, NULL)) < 0)
+				break;
+		switch (c)
+		{
+		case 'h':
+				morehelp++;
+				break;
+		case 'p':
+				gPeriodSize = atoi(optarg);
+				break;
+		case 'v':
+				gVerbose = 1;
+				break;
+		case 'f':
+				free(gPartialFilename);
+				gPartialFilename = strdup(optarg);
+				break;
+		case 'k':
+				forceKeyboard = true;
+				break;
+		case 'i':
+				gAudioIn = (atoi(optarg)==0) ? false : true;
+				break;
+		case 's':
+				forceSensors = true;
+				break;
+		case 'A':
+				useAudioTest = true;
+				break;
+		case 'S':
+				useNewSensors = true;
+				break;
+		case 'Q':
+				touchSensor0Address = atoi(optarg);
+				break;
+		case 'R':
+				touchSensor1Address = atoi(optarg);
+				break;
+		case 'l':
+				tmp = atoi(optarg);
+				if(tmp==0)
+					forceLog = false;
+				else if(tmp>0)
+					forceLog = true;
+				break;
+		case 'u':
+				tmp = atoi(optarg);
+				if(tmp==0)
+					useSD = false;
+				else if(tmp>0)
+					useSD = true;
+				break;
+		case 'o':
+				oscBnkOversampling = atoi(optarg);
+				break;
+		case 'n':
+				gId = *optarg;
+				cout << "-set box number to: " << gId << endl;
+				break;
+		case 'g':
+				gGroup = *optarg;
+				cout << "-set group to: " << gId << endl;
+				break;
+		default:
+				break;
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	RT_TASK rtSensorThread;
+	const char rtSensorThreadName[] = "dbox-sensor";
+	int oscBankHopSize;
+
+	// Parse command-line arguments
+	args.argc = argc;
+	args.argv = argv;
+	parseArguments(args);
+
+	setVerboseLevel(gVerbose);
+	if(gVerbose == 1 && useAudioTest)
+		cout << "main() : running in audio test mode" << endl;
+
+	// Load sound files from directory
+	if(initSoundFiles() != 0)
+		return -1;
+
+	oscBankHopSize = gOscBanks[gCurrentOscBank]->getHopSize()/gOscBanks[gCurrentOscBank]->getMinSpeed();
+
+	// Initialise the audio device
+	if(initAudio(gPeriodSize, 1, &oscBankHopSize) != 0)
+		return -1;
+
+	// Initialise the status LED
+	if(!gStatusLED.init(kStatusLEDPin)) {
+		if(gVerbose)
+			cout << "Couldn't initialise status LED pin\n";
+	}
+
+	// Free file name string which is no longer needed
+	if(gPartialFilename != 0)
+		free(gPartialFilename);
+
+	if(!useAudioTest) {
+		if(initSensorLoop(touchSensor0Address, touchSensor1Address, useNewSensors) != 0)
+			return -1;
+	}
+
+	if(gVerbose == 1)
+		cout << "main() : creating audio thread" << endl;
+
+	if(startAudio()) {
+		cout << "Error: unable to start real-time audio" << endl;
+		return -1;
+	}
+
+	// LED on...
+	gStatusLED.on();
+
+	if(forceSensors && !useAudioTest) {
+		if(gVerbose==1)
+			cout << "main() : creating control thread" << endl;
+
+		if(rt_task_create(&rtSensorThread, rtSensorThreadName, 0, 95, T_JOINABLE | T_FPU)) {
+			  cout << "Error:unable to create Xenomai control thread" << endl;
+			  return -1;
+		}
+		if(rt_task_start(&rtSensorThread, &sensorLoop, 0)) {
+			  cout << "Error:unable to start Xenomai control thread" << endl;
+			  return -1;
+		}
+	}
+
+	if(forceKeyboard) {
+		if(gVerbose==1)
+			cout << "main() : creating keyboard thread" << endl;
+
+		if ( pthread_create(&keyboardThread, NULL, keyboardLoop, NULL) ) {
+		  cout << "Error:unable to create keyboard thread" << endl;
+		  return -1;
+		}
+	}
+
+	if(forceLog) {
+		if(gVerbose==1)
+			cout << "main() : creating log thread" << endl;
+
+		if(initLogLoop()!=0) {
+			cout << "Error:unable to create log thread" << endl;
+			return -1;
+		}
+
+		if ( pthread_create(&logThread, NULL, logLoop, NULL) ) {
+		  cout << "Error:unable to create keyboard thread" << endl;
+		  return -1;
+		}
+	}
+
+	// Set up interrupt handler to catch Control-C
+	signal(SIGINT, interrupt_handler);
+
+	// load all other files into oscBanks
+	loadAudioFiles(false);
+	cout << "Finished loading analysis files\n";
+	gIsLoading = false;
+
+	// Run until told to stop
+	while(!gShouldStop) {
+		usleep(100000);
+	}
+
+	stopAudio();
+
+	if(!useAudioTest)
+		rt_task_join(&rtSensorThread);
+
+	cleanupAudio();
+
+	pthread_join( keyboardThread, NULL);
+	pthread_join( logThread, NULL);
+
+	for(unsigned int i = 0; i < gOscBanks.size(); i++)
+		delete gOscBanks[i];
+
+	NE10_FREE(filterState[0]);
+	NE10_FREE(filterState[1]);
+	NE10_FREE(filterIn[0]);
+	NE10_FREE(filterIn[1]);
+	NE10_FREE(filterOut[0]);
+	NE10_FREE(filterOut[1]);
+
+	printf("Program ended\nBye bye\n");
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/prio.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,48 @@
+/*
+ * prio.cpp
+ *
+ *  Created on: May 14, 2014
+ *      Author: Victor Zappi
+ */
+
+#include "prio.h"
+using namespace std;
+//-----------------------------------------------------------------------------------------------------------
+// set wanted real-time priority to this thread
+//-----------------------------------------------------------------------------------------------------------
+void set_realtime_priority(int order)
+{
+    int ret;
+
+    // We'll operate on the currently running thread.
+    pthread_t this_thread = pthread_self();
+    // struct sched_param is used to store the scheduling priority
+	struct sched_param params;
+	// We'll set the priority to the maximum.
+	params.sched_priority = sched_get_priority_max(SCHED_FIFO) - order;
+
+	// Attempt to set thread real-time priority to the SCHED_FIFO policy
+	ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params);
+	if (ret != 0) {
+		// Print the error
+		cout << "Unsuccessful in setting thread realtime prio" << endl;
+		return;
+	}
+
+	// Now verify the change in thread priority
+    int policy = 0;
+    ret = pthread_getschedparam(this_thread, &policy, &params);
+    if (ret != 0) {
+        cout << "Couldn't retrieve real-time scheduling parameters" << endl;
+        return;
+    }
+
+    // Check the correct policy was applied
+    if(policy != SCHED_FIFO) {
+        cout << "Scheduling is NOT SCHED_FIFO!" << endl;
+    }
+}
+
+//-----------------------------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/prio.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,22 @@
+/*
+ * prio.h
+ *
+ *  Created on: May 14, 2014
+ *      Author: Victor Zappi
+ */
+
+#ifndef PRIO_H_
+#define PRIO_H_
+
+
+#include <pthread.h>
+#include <sched.h>
+#include <iostream>
+
+//-----------------------------------------------------------------------------------------------------------
+// set maximum real-time priority to this thread
+//-----------------------------------------------------------------------------------------------------------
+void set_realtime_priority(int order);
+//-----------------------------------------------------------------------------------------------------------
+
+#endif /* PRIO_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/render.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,841 @@
+/*
+ * render.cpp
+ *
+ *  Created on: May 28, 2014
+ *      Author: Victor Zappi
+ */
+
+#include "../../include/RTAudio.h"
+#include "../../include/PRU.h"
+#include "StatusLED.h"
+#include "config.h"
+#include "OscillatorBank.h"
+#include "FeedbackOscillator.h"
+#include "ADSR.h"
+#include "FIRfilter.h"
+#include <assert.h>
+#include <cmath>
+#include <vector>
+
+#undef DBOX_CAPE_TEST
+
+#define N_OCT		4.0	// maximum number of octaves on sensor 1
+
+extern vector<OscillatorBank*> gOscBanks;
+extern int gCurrentOscBank;
+extern int gNextOscBank;
+extern PRU *gPRU;
+extern StatusLED gStatusLED;
+extern bool gIsLoading;
+extern bool gAudioIn;
+extern int gPeriodSize;
+int gChannels = 2;
+
+float *gOscillatorBuffer1, *gOscillatorBuffer2;
+float *gOscillatorBufferRead, *gOscillatorBufferWrite;
+int gOscillatorBufferReadPointer		= 0;
+int gOscillatorBufferReadCurrentSize	= 0;
+int gOscillatorBufferWriteCurrentSize	= 0;
+bool gOscillatorNeedsRender				= false;
+
+int gMatrixSampleCount = 0;		// How many samples have elapsed on the matrix
+
+// Wavetable which changes in response to an oscillator
+float *gDynamicWavetable;
+int gDynamicWavetableLength;
+bool gDynamicWavetableNeedsRender = false;
+
+// These variables handle the hysteresis oscillator used for setting the playback speed
+bool gSpeedHysteresisOscillatorRising	= false;
+int gSpeedHysteresisLastTrigger			= 0;
+
+// These variables handle the feedback oscillator used for controlling the wavetable
+FeedbackOscillator gFeedbackOscillator;
+float *gFeedbackOscillatorTable;
+int gFeedbackOscillatorTableLength;
+
+// This comes from sensor.cpp where it records the most recent touch location on
+// sensor 0.
+extern float gSensor0LatestTouchPos;
+extern int gSensor0LatestTouchNum;
+uint16_t gPitchLatestInput = 0;
+
+extern float gSensor1LatestTouchPos[];
+//extern float gSensor1LatestTouchSizes[];
+extern int gSensor1LatestTouchCount;
+extern int gSensor1LatestTouchIndex;
+int gSensor1LastTouchIndex		= -1;
+int gSensor1InputDelayCounter	= -1;
+int gSensor1InputIndex			= 0;
+float gSensor1MatrixTouchPos[5]	= {0};
+
+// FSR value from matrix input
+extern int gLastFSRValue;
+
+// Loop points from matrix input 4
+const int gLoopPointsInputBufferSize	= 256;
+uint16_t gLoopPointsInputBuffer[gLoopPointsInputBufferSize];
+int gLoopPointsInputBufferPointer		= 0;
+int gLoopPointMin = 0, gLoopPointMax	= 0;
+
+// multiplier to activate or mute audio in
+int audioInStatus = 0;
+
+// xenomai timer
+SRTIME prevChangeNs = 0;
+
+// pitch vars
+float octaveSplitter;
+u_int16_t semitones[((int)N_OCT*12)+1];
+float deltaTouch	= 0;
+float deltaWeightP	= 0.5;
+float deltaWeightI	= 0.0005;
+
+// filter vars
+ne10_fir_instance_f32_t filter[2];
+ne10_float32_t *filterIn[2];
+ne10_float32_t *filterOut[2];
+ne10_uint32_t blockSize;
+ne10_float32_t *filterState[2];
+ne10_float32_t prevFiltered[2];
+int filterGain = 80;
+ADSR PeakBurst[2];
+float peak[2];
+float peakThresh = 0.2;
+
+// Tasks for lower-priority calculation
+AuxiliaryTask gMediumPriorityRender, gLowPriorityRender;
+
+
+extern "C" {
+	// Function prototype for ARM assembly implementation of oscillator bank
+	void oscillator_bank_neon(int numAudioFrames, float *audioOut,
+							  int activePartialNum, int lookupTableSize,
+							  float *phases, float *frequencies, float *amplitudes,
+							  float *freqDerivatives, float *ampDerivatives,
+							  float *lookupTable);
+
+	void wavetable_interpolate_neon(int numSamplesIn, int numSamplesOut,
+	                              float *tableIn, float *tableOut);
+}
+
+void wavetable_interpolate(int numSamplesIn, int numSamplesOut,
+                              float *tableIn, float *tableOut,
+                              float *sineTable, float sineMix);
+
+inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold,
+									uint16_t fallingThreshold, bool *rising);
+
+#ifdef DBOX_CAPE_TEST
+void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut);
+#endif
+
+bool initialise_render(int numChannels, int numMatrixFramesPerPeriod, int numAudioFramesPerPeriod, float matrixSampleRate, float audioSampleRate, void *userData) {
+	gChannels = numChannels;
+	int oscBankHopSize = *(int *)userData;
+
+	// Allocate two buffers for rendering oscillator bank samples
+	// One will be used for writing in the background while the other is used for reading
+	// on the audio thread. 8-byte alignment needed for the NEON code.
+	if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * gChannels * sizeof(float))) {
+		printf("Error allocating render buffers\n");
+		return false;
+	}
+	if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * gChannels * sizeof(float))) {
+		printf("Error allocating render buffers\n");
+		return false;
+	}
+	gOscillatorBufferWrite	= gOscillatorBuffer1;
+	gOscillatorBufferRead	= gOscillatorBuffer2;
+
+	memset(gOscillatorBuffer1, 0, oscBankHopSize * gChannels * sizeof(float));
+	memset(gOscillatorBuffer2, 0, oscBankHopSize * gChannels * sizeof(float));
+
+	// Initialise the dynamic wavetable used by the oscillator bank
+	// It should match the size of the static one already allocated in the OscillatorBank object
+	// Don't forget a guard point at the end of the table
+	gDynamicWavetableLength = gOscBanks[gCurrentOscBank]->lookupTableSize;
+	if(posix_memalign((void **)&gDynamicWavetable, 8, (gDynamicWavetableLength + 1) * sizeof(float))) {
+		printf("Error allocating wavetable\n");
+		return false;
+	}
+
+	gFeedbackOscillator.initialise(8192, 10.0, matrixSampleRate);
+
+	for(int n = 0; n < gDynamicWavetableLength + 1; n++)
+		gDynamicWavetable[n] = 0;
+
+	// pitch
+	float midPos		= (float)65535/2.0;
+	octaveSplitter		= round((float)65535/(N_OCT));
+	int numOfSemi		= 12*N_OCT;
+	int middleSemitone	= 12*N_OCT/2;
+	int lastSemitone	= middleSemitone+numOfSemi/2;
+	float inc 			= (float)65535/(N_OCT*12.0);
+	int i 				= -1;
+	for(int semi=middleSemitone; semi<=lastSemitone; semi++)
+		semitones[semi] = ( midPos + (++i)*inc) + 0.5;
+	i 					= 0;
+	for(int semi=middleSemitone-1; semi>=0; semi--)
+		semitones[semi] = ( midPos - (++i)*inc) + 0.5;
+
+	if(gAudioIn)
+		audioInStatus = 1;
+
+	// filter
+	blockSize		= 2*gPeriodSize;
+	filterState[0]	= (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t));
+	filterState[1]	= (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t));
+	filterIn[0]		= (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t));
+	filterIn[1]		= (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t));
+	filterOut[0]	= (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t));
+	filterOut[1]	= (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t));
+	ne10_fir_init_float(&filter[0], FILTER_TAP_NUM, filterTaps, filterState[0], blockSize);
+	ne10_fir_init_float(&filter[1], FILTER_TAP_NUM, filterTaps, filterState[1], blockSize);
+
+	// peak outputs
+	PeakBurst[0].setAttackRate(.00001 * matrixSampleRate);
+	PeakBurst[1].setAttackRate(.00001 * matrixSampleRate);
+	PeakBurst[0].setDecayRate(.5 * matrixSampleRate);
+	PeakBurst[1].setDecayRate(.5 * matrixSampleRate);
+	PeakBurst[0].setSustainLevel(0.0);
+	PeakBurst[1].setSustainLevel(0.0);
+
+	// Initialise auxiliary tasks
+	if((gMediumPriorityRender = createAuxiliaryTaskLoop(&render_medium_prio, 90, "dbox-calculation-medium")) == 0)
+		return false;
+	if((gLowPriorityRender = createAuxiliaryTaskLoop(&render_low_prio, 85, "dbox-calculation-low")) == 0)
+		return false;
+
+	return true;
+}
+
+void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut)
+{
+#ifdef DBOX_CAPE_TEST
+	render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut);
+#else
+	if(gOscBanks[gCurrentOscBank]->state==bank_toreset)
+		gOscBanks[gCurrentOscBank]->resetOscillators();
+
+	if(gOscBanks[gCurrentOscBank]->state==bank_playing)
+	{
+		assert(gChannels == 2);
+
+#ifdef OLD_OSCBANK
+		memset(audioOut, 0, numAudioFrames * gChannels * sizeof(float));
+
+		/* Render the oscillator bank. The oscillator bank function is written in NEON assembly
+		 * and it strips out all extra checks, so find out in advance whether we can render a whole
+		 * block or whether the frame will increment in the middle of this buffer.
+		 */
+
+		int framesRemaining = numAudioFrames;
+		float *audioOutWithOffset = audioOut;
+
+		while(framesRemaining > 0) {
+			if(gOscBanks[gCurrentOscBank]->hopCounter >= framesRemaining) {
+				/* More frames left in this hop than we need this time. Render and finish */
+				oscillator_bank_neon(framesRemaining, audioOutWithOffset,
+									 gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize,
+									 gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies,
+									 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes,
+									 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives,
+									 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives,
+									 gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/);
+				gOscBanks[gCurrentOscBank]->hopCounter -= framesRemaining;
+				if(gOscBanks[gCurrentOscBank]->hopCounter <= 0)
+					gOscBanks[gCurrentOscBank]->nextHop();
+				framesRemaining = 0;
+			}
+			else {
+				/* More frames to render than are left in this hop. Render and decrement the
+				 * number of remaining frames; then advance to the next oscillator frame.
+				 */
+				oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, audioOutWithOffset,
+									 gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize,
+									 gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies,
+									 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes,
+									 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives,
+									 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives,
+									 gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/);
+				framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter;
+				audioOutWithOffset += gChannels * gOscBanks[gCurrentOscBank]->hopCounter;
+				gOscBanks[gCurrentOscBank]->sampleCount += gOscBanks[gCurrentOscBank]->hopCounter;
+				gOscBanks[gCurrentOscBank]->nextHop();
+			}
+		}
+#else
+		for(int n = 0; n < numAudioFrames; n++) {
+			audioOut[2*n] 	  = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+audioIn[2*n]*audioInStatus;
+			audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+audioIn[2*n+1]*audioInStatus;
+
+			filterIn[0][n] = fabs(audioIn[2*n]);	// rectify for peak detection in 1
+			filterIn[1][n] = fabs(audioIn[2*n+1]);	// rectify for peak detection in 2
+
+			/* FIXME why doesn't this work? */
+			/*
+			if(gOscillatorBufferReadPointer == gOscillatorBufferCurrentSize/2) {
+				gOscillatorNeedsRender = true;
+				scheduleAuxiliaryTask(gLowPriorityRender);
+			} */
+
+			if(gOscillatorBufferReadPointer >= gOscillatorBufferReadCurrentSize) {
+				// Finished reading from the buffer: swap to the next buffer
+				if(gOscillatorBufferRead == gOscillatorBuffer1) {
+					gOscillatorBufferRead = gOscillatorBuffer2;
+					gOscillatorBufferWrite = gOscillatorBuffer1;
+				}
+				else {
+					gOscillatorBufferRead = gOscillatorBuffer1;
+					gOscillatorBufferWrite = gOscillatorBuffer2;
+				}
+
+				// New buffer size is whatever finished writing last hop
+				gOscillatorBufferReadCurrentSize = gOscillatorBufferWriteCurrentSize;
+				gOscillatorBufferReadPointer = 0;
+
+				gOscillatorNeedsRender = true;
+				scheduleAuxiliaryTask(gMediumPriorityRender);
+			}
+		}
+#endif
+	}
+	else
+	{
+		for(int n = 0; n < numAudioFrames; n++) {
+			audioOut[2*n] 	  = audioIn[2*n]*audioInStatus;
+			audioOut[2*n + 1] = audioIn[2*n+1]*audioInStatus;
+
+			filterIn[0][n] = fabs(audioIn[2*n]);	// rectify for peak detection in 1
+			filterIn[1][n] = fabs(audioIn[2*n+1]);	// rectify for peak detection in 2
+		}
+	}
+
+	// low pass filter audio in 1 and 2 for peak detection
+	ne10_fir_float_neon(&filter[0], filterIn[0], filterOut[0], blockSize);
+	ne10_fir_float_neon(&filter[1], filterIn[1], filterOut[1], blockSize);
+
+	for(int n = 0; n < numMatrixFrames; n++) {
+
+
+		/* Matrix Out 0, In 0
+		 *
+		 * CV loop
+		 * Controls pitch of sound
+		 */
+		int touchPosInt = gSensor0LatestTouchPos * 65536.0;
+		if(touchPosInt < 0) touchPosInt = 0;
+		if(touchPosInt > 65535) touchPosInt = 65535;
+		matrixOut[n*8 + DAC_PIN0] = touchPosInt;
+
+		gPitchLatestInput = matrixIn[n*8 + ADC_PIN0];
+
+
+		/* Matrix Out 7
+		 *
+		 * Loop feedback with Matrix In 0
+		 * Controls discreet pitch
+		 */
+		float deltaTarget = 0;
+		int semitoneIndex = 0;
+		if(gSensor0LatestTouchNum>0)
+		{
+			// current pitch is gPitchLatestInput, already retrieved
+			semitoneIndex	= (  ( (float)gPitchLatestInput / 65535)*12*N_OCT  )+0.5;	// closest semitone
+			deltaTarget		= (semitones[semitoneIndex]-gPitchLatestInput);				// delta between pitch and target
+			deltaTouch 		+= deltaTarget*deltaWeightI;								// update feedback [previous + current]
+		}
+		else
+			deltaTouch = 0;
+
+		int nextOut = touchPosInt  + deltaTarget*deltaWeightP + deltaTouch;			// add feedback to touch -> next out
+		if(nextOut < 0) nextOut = 0;												// clamp
+		if(nextOut > 65535) nextOut = 65535;										// clamp
+		matrixOut[n*8 + DAC_PIN7] = nextOut;										// send next nextOut
+
+
+		/*
+		 * Matrix Out 1, In 1
+		 *
+		 * Hysteresis (comparator) oscillator
+		 * Controls speed of playback
+		 */
+		bool wasRising = gSpeedHysteresisOscillatorRising;
+		matrixOut[n*8 + DAC_PIN1] = hysteresis_oscillator(matrixIn[n*8 + ADC_PIN1], 48000, 16000, &gSpeedHysteresisOscillatorRising);
+
+		// Find interval of zero crossing
+		if(wasRising && !gSpeedHysteresisOscillatorRising) {
+			int interval = gMatrixSampleCount - gSpeedHysteresisLastTrigger;
+
+			// Interval since last trigger will be the new hop size; calculate to set speed
+			if(interval < 1)
+				interval = 1;
+			//float speed = (float)gOscBanks[gCurrentOscBank]->getHopSize() / (float)interval;
+			float speed = 144.0 / interval;	// Normalise to a fixed expected speed
+			gOscBanks[gCurrentOscBank]->setSpeed(speed);
+
+			gSpeedHysteresisLastTrigger = gMatrixSampleCount;
+		}
+
+		/*
+		 * Matrix Out 2, In 2
+		 *
+		 * Feedback (phase shift) oscillator
+		 * Controls wavetable used for oscillator bank
+		 */
+
+		int tableLength = gFeedbackOscillator.process(matrixIn[n*8 + ADC_PIN2], &matrixOut[n*8 + DAC_PIN2]);
+		if(tableLength != 0) {
+			gFeedbackOscillatorTableLength = tableLength;
+			gFeedbackOscillatorTable = gFeedbackOscillator.wavetable();
+			gDynamicWavetableNeedsRender = true;
+			scheduleAuxiliaryTask(gLowPriorityRender);
+		}
+
+		/*
+		 * Matrix Out 3, In 3
+		 *
+		 * CV loop with delay for time alignment
+		 * Touch positions from sensor 1
+		 * Change every 32 samples (ca. 1.5 ms)
+		 */
+		volatile int touchCount = gSensor1LatestTouchCount;
+		if(touchCount == 0)
+			matrixOut[n*8 + DAC_PIN3] = 0;
+		else {
+			int touchIndex = (gMatrixSampleCount >> 5) % touchCount;
+			matrixOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f;
+			if(touchIndex != gSensor1LastTouchIndex) {
+				// Just changed to a new touch output. Reset the counter.
+				// It will take 2*matrixFrames samples for this output to come back to the
+				// ADC input. But we also want to read near the end of the 32 sample block;
+				// let's say 24 samples into it.
+
+				// FIXME this won't work for p > 2
+				gSensor1InputDelayCounter = 24 + 2*numMatrixFrames;
+				gSensor1InputIndex = touchIndex;
+			}
+			gSensor1LastTouchIndex = touchIndex;
+		}
+
+		if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) {
+			gSensor1MatrixTouchPos[gSensor1InputIndex] = (float)matrixIn[n*8 + ADC_PIN3] / 65536.0f;
+		}
+
+		/* Matrix Out 4
+		 *
+		 * Sensor 1 last pos
+		 */
+		touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex] * 65536.0;
+		if(touchPosInt < 0) touchPosInt = 0;
+		if(touchPosInt > 65535) touchPosInt = 65535;
+		matrixOut[n*8 + DAC_PIN4] = touchPosInt;
+
+		/* Matrix In 4
+		 *
+		 * Loop points selector
+		 */
+		gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = matrixIn[n*8 + ADC_PIN4];
+		if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) {
+			// Find min and max values
+			uint16_t loopMax = 0, loopMin = 65535;
+			for(int i = 0; i < gLoopPointsInputBufferSize; i++) {
+				if(gLoopPointsInputBuffer[i] < loopMin)
+					loopMin = gLoopPointsInputBuffer[i];
+				if(gLoopPointsInputBuffer[i] > loopMax/* && gLoopPointsInputBuffer[i] != 65535*/)
+					loopMax = gLoopPointsInputBuffer[i];
+			}
+
+			if(loopMin >= loopMax)
+				loopMax = loopMin;
+
+			gLoopPointMax = loopMax;
+			gLoopPointMin = loopMin;
+			gLoopPointsInputBufferPointer = 0;
+		}
+
+		/* Matrix Out 5
+		 *
+		 * Audio In 1 peak detection and peak burst output
+		 */
+
+		filterOut[0][n*2+1]	*= filterGain;
+		float burstOut		= PeakBurst[0].getOutput();
+		if( burstOut < 0.1)
+		{
+			if( (prevFiltered[0]>=peakThresh) && (prevFiltered[0]>=filterOut[0][n*2+1]) )
+			{
+				peak[0] = prevFiltered[0];
+				PeakBurst[0].gate(1);
+			}
+		}
+
+		PeakBurst[0].process(1);
+
+		int convAudio = burstOut*peak[0]*65535;
+		matrixOut[n*8 + DAC_PIN5] = convAudio;
+		prevFiltered[0] = filterOut[0][n*2+1];
+		if(prevFiltered[0]>1)
+			prevFiltered[0] = 1;
+
+		/* Matrix In 5
+		 *
+		 * Dissonance, via changing frequency motion of partials
+		 */
+		float amount = (float)matrixIn[n*8 + ADC_PIN5] / 65536.0f;
+		gOscBanks[gCurrentOscBank]->freqMovement = 1-amount;
+
+
+
+
+		/* Matrix Out 6
+		 *
+		 * Audio In 2 peak detection and peak burst output
+		 */
+
+		filterOut[1][n*2+1]	*= filterGain;
+		burstOut			= PeakBurst[1].getOutput();
+		if( burstOut < 0.1)
+		{
+			if( (prevFiltered[1]>=peakThresh) && (prevFiltered[1]>=filterOut[1][n*2+1]) )
+			{
+				peak[1] = prevFiltered[1];
+				PeakBurst[1].gate(1);
+			}
+		}
+
+		PeakBurst[1].process(1);
+
+		convAudio = burstOut*peak[1]*65535;
+		matrixOut[n*8 + DAC_PIN6] = convAudio;
+		prevFiltered[1] = filterOut[1][n*2+1];
+		if(prevFiltered[1]>1)
+			prevFiltered[1] = 1;
+
+		/* Matrix In 6
+		 *
+		 * Sound selector
+		 */
+		if(!gIsLoading) {
+			// Use hysteresis to avoid jumping back and forth between sounds
+			if(gOscBanks.size() > 1) {
+				int input = matrixIn[n*8 + ADC_PIN6];
+				const int hystValue = 16000;
+
+				int upHysteresisValue = ((gCurrentOscBank + 1) * 65536 + hystValue) / gOscBanks.size();
+				int downHysteresisValue = (gCurrentOscBank * 65536 - hystValue) / gOscBanks.size();
+
+				if(input > upHysteresisValue || input < downHysteresisValue) {
+					gNextOscBank = input * gOscBanks.size() / 65536;
+					if(gNextOscBank < 0)
+						gNextOscBank = 0;
+					if((unsigned)gNextOscBank >= gOscBanks.size())
+						gNextOscBank = gOscBanks.size() - 1;
+				}
+			}
+		}
+
+		/*
+		 * Matrix In 7
+		 *
+		 * FSR from primary touch sensor
+		 * Value ranges from 0-1799
+		 */
+		gLastFSRValue = matrixIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0);
+		//gLastFSRValue = 1799 - matrixIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0);
+		//dbox_printf("%i\n",gLastFSRValue);
+
+		gMatrixSampleCount++;
+	}
+
+#endif /* DBOX_CAPE_TEST */
+}
+
+// Medium-priority render function used for audio hop calculations
+void render_medium_prio()
+{
+
+	if(gOscillatorNeedsRender) {
+		gOscillatorNeedsRender = false;
+
+		/* Render one frame into the write buffer */
+		memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * gChannels * sizeof(float));
+
+		oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite,
+							 gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize,
+							 gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies,
+							 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes,
+							 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives,
+							 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives,
+							 /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable);
+
+		gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * gChannels;
+
+		/* Update the pitch right before the hop
+		 * Total CV range +/- N_OCT octaves
+		 */
+		float pitch = (float)gPitchLatestInput / octaveSplitter - N_OCT/2;
+		//gOscBanks[gCurrentOscBank]->pitchMultiplier = powf(2.0f, pitch);
+		gOscBanks[gCurrentOscBank]->pitchMultiplier = pow(2.0f, pitch);
+
+#ifdef FIXME_LATER // This doesn't work very well yet
+		gOscBanks[gCurrentOscBank]->filterNum = gSensor1LatestTouchCount;
+		float freqScaler = gOscBanks[gCurrentOscBank]->getFrequencyScaler();
+		for(int i=0; i < gOscBanks[gCurrentOscBank]->filterNum; i++)
+		{
+			// touch pos is linear but freqs are log
+			gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((expf(gSensor1MatrixTouchPos[i]*4)-1)/(expf(4)-1))*gOscBanks[gCurrentOscBank]->filterMaxF*freqScaler;
+			gOscBanks[gCurrentOscBank]->filterQ[i] = gSensor1LatestTouchSizes[i];
+			if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler)
+				gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(gOscBanks[gCurrentOscBank]->filterMaxF-500)*freqScaler );
+			else
+				gOscBanks[gCurrentOscBank]->filterPadding[i] = 1;
+		}
+#endif
+
+		RTIME ticks		= rt_timer_read();
+		SRTIME ns		= rt_timer_tsc2ns(ticks);
+		SRTIME delta 	= ns-prevChangeNs;
+
+		// switch to next bank cannot be too frequent, to avoid seg fault! [for example sef fault happens when removing both VDD and GND from breadboard]
+		if(gNextOscBank != gCurrentOscBank && delta>100000000) {
+
+			/*printf("ticks %llu\n", (unsigned long long)ticks);
+			printf("ns %llu\n", (unsigned long long)ns);
+			printf("prevChangeNs %llu\n", (unsigned long long)prevChangeNs);
+			printf("-------------------------->%llud\n", (unsigned long long)(ns-prevChangeNs));*/
+
+			prevChangeNs = ns;
+			dbox_printf("Changing to bank %d...\n", gNextOscBank);
+			if(gOscBanks[gCurrentOscBank]->state==bank_playing){
+				gOscBanks[gCurrentOscBank]->stop();
+			}
+
+			gCurrentOscBank = gNextOscBank;
+			gOscBanks[gCurrentOscBank]->hopNumTh = 0;
+		}
+		else {
+			/* Advance to the next oscillator frame */
+			gOscBanks[gCurrentOscBank]->nextHop();
+		}
+	}
+}
+
+// Lower-priority render function which performs matrix calculations
+// State should be transferred in via global variables
+void render_low_prio()
+{
+	gPRU->setGPIOTestPin();
+	if(gDynamicWavetableNeedsRender) {
+		// Find amplitude of wavetable
+		float meanAmplitude = 0;
+		float sineMix;
+
+		for(int i = 0; i < gFeedbackOscillatorTableLength; i++) {
+			//meanAmplitude += fabsf(gFeedbackOscillatorTable[i]);
+			meanAmplitude += fabs(gFeedbackOscillatorTable[i]);
+		}
+		meanAmplitude /= (float)gFeedbackOscillatorTableLength;
+
+		if(meanAmplitude > 0.35)
+			sineMix = 0;
+		else
+			sineMix = (.35 - meanAmplitude) / .35;
+
+		//dbox_printf("amp %f mix %f\n", meanAmplitude, sineMix);
+
+		// Copy to main wavetable
+		wavetable_interpolate(gFeedbackOscillatorTableLength, gDynamicWavetableLength,
+				gFeedbackOscillatorTable, gDynamicWavetable,
+				gOscBanks[gCurrentOscBank]->lookupTable, sineMix);
+	}
+
+	if(gLoopPointMin >= 60000 && gLoopPointMax >= 60000) {
+		// KLUDGE!
+		if(gCurrentOscBank == 0)
+			gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1);
+		else
+			gOscBanks[gCurrentOscBank]->setLoopHops(5, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.7) - 1);
+	}
+	else {
+		float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop() / 65535.0;
+		float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop() / 65535.0;
+
+		int intLoopPointMin = normLoopPointMin;
+		if(intLoopPointMin < 1)
+			intLoopPointMin = 1;
+		int intLoopPointMax = normLoopPointMax;
+		if(intLoopPointMax <= intLoopPointMin)
+			intLoopPointMax = intLoopPointMin + 1;
+		if(intLoopPointMax > gOscBanks[gCurrentOscBank]->getLastHop() - 1)
+			intLoopPointMax =  gOscBanks[gCurrentOscBank]->getLastHop() - 1;
+
+		//dbox_printf("Loop points %d-%d / %d-%d\n", gLoopPointMin, gLoopPointMax, intLoopPointMin, intLoopPointMax);
+
+		/* WORKS, jsut need to fix the glitch when jumps!
+		 * *int currentHop = gOscBanks[gCurrentOscBank]->getCurrentHop();
+		if(currentHop < intLoopPointMin -1 )
+			gOscBanks[gCurrentOscBank]->setJumpHop(intLoopPointMin + 1);
+		else if(currentHop > intLoopPointMax + 1)
+			gOscBanks[gCurrentOscBank]->setJumpHop(intLoopPointMax - 1);*/
+		gOscBanks[gCurrentOscBank]->setLoopHops(intLoopPointMin, intLoopPointMax);
+	}
+
+	if(gIsLoading)
+		gStatusLED.blink(25, 75);	// Blink quickly until load finished
+	else
+		gStatusLED.blink(250 / gOscBanks[gCurrentOscBank]->getSpeed(), 250 / gOscBanks[gCurrentOscBank]->getSpeed());
+	gPRU->clearGPIOTestPin();
+
+//	static int counter = 32;
+//	if(--counter == 0) {
+//		for(int i = 0; i < gLoopPointsInputBufferSize; i++) {
+//			dbox_printf("%d ", gLoopPointsInputBuffer[i]);
+//			if(i % 32 == 31)
+//				dbox_printf("\n");
+//		}
+//		dbox_printf("\n\n");
+//		counter = 32;
+//	}
+
+	//dbox_printf("min %d max %d\n", gLoopPointMin, gLoopPointMax);
+}
+
+// Clean up at the end of render
+void cleanup_render()
+{
+	free(gOscillatorBuffer1);
+	free(gOscillatorBuffer2);
+	free(gDynamicWavetable);
+}
+
+// Interpolate one wavetable into another. The output size
+// does not include the guard point at the end which will be identical
+// to the first point
+void wavetable_interpolate(int numSamplesIn, int numSamplesOut,
+                           float *tableIn, float *tableOut,
+                           float *sineTable, float sineMix)
+{
+	float fractionalScaler = (float)numSamplesIn / (float)numSamplesOut;
+
+	for(int k = 0; k < numSamplesOut; k++) {
+		float fractionalIndex = (float) k * fractionalScaler;
+		//int sB = (int)floorf(fractionalIndex);
+		int sB = (int)floor(fractionalIndex);
+		int sA = sB + 1;
+		if(sA >= numSamplesIn)
+			sA = 0;
+		float fraction = fractionalIndex - sB;
+		tableOut[k] = fraction * tableIn[sA] + (1.0f - fraction) * tableIn[sB];
+		tableOut[k] = sineMix * sineTable[k] + (1.0 - sineMix) * tableOut[k];
+	}
+
+	tableOut[numSamplesOut] = tableOut[0];
+}
+
+// Create a hysteresis oscillator with a matrix input and output
+inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold, uint16_t fallingThreshold, bool *rising)
+{
+	uint16_t value;
+
+	if(*rising) {
+		if(input > risingThreshold) {
+			*rising = false;
+			value = 0;
+		}
+		else
+			value = 65535;
+	}
+	else {
+		if(input < fallingThreshold) {
+			*rising = true;
+			value = 65535;
+		}
+		else
+			value = 0;
+	}
+
+	return value;
+}
+
+#ifdef DBOX_CAPE_TEST
+// Test the functionality of the D-Box cape by checking each input and output
+// Loopback cable from ADC to DAC needed
+void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut)
+{
+	static float phase = 0.0;
+	static int sampleCounter = 0;
+	static int invertChannel = 0;
+
+	// Play a sine wave on the audio output
+	for(int n = 0; n < numAudioFrames; n++) {
+		audioOut[2*n] = audioOut[2*n + 1] = 0.5*sinf(phase);
+		phase += 2.0 * M_PI * 440.0 / 44100.0;
+		if(phase >= 2.0 * M_PI)
+			phase -= 2.0 * M_PI;
+	}
+
+	for(int n = 0; n < numMatrixFrames; n++) {
+		// Change outputs every 512 samples
+		if(sampleCounter < 512) {
+			for(int k = 0; k < 8; k++) {
+				if(k == invertChannel)
+					matrixOut[n*8 + k] = 50000;
+				else
+					matrixOut[n*8 + k] = 0;
+			}
+		}
+		else {
+			for(int k = 0; k < 8; k++) {
+				if(k == invertChannel)
+					matrixOut[n*8 + k] = 0;
+				else
+					matrixOut[n*8 + k] = 50000;
+			}
+		}
+
+		// Read after 256 samples: input should be low
+		if(sampleCounter == 256) {
+			for(int k = 0; k < 8; k++) {
+				if(k == invertChannel) {
+					if(matrixIn[n*8 + k] < 50000) {
+						dbox_printf("FAIL channel %d -- output HIGH input %d (inverted)\n", k, matrixIn[n*8 + k]);
+					}
+				}
+				else {
+					if(matrixIn[n*8 + k] > 2048) {
+						dbox_printf("FAIL channel %d -- output LOW input %d\n", k, matrixIn[n*8 + k]);
+					}
+				}
+			}
+		}
+		else if(sampleCounter == 768) {
+			for(int k = 0; k < 8; k++) {
+				if(k == invertChannel) {
+					if(matrixIn[n*8 + k] > 2048) {
+						dbox_printf("FAIL channel %d -- output LOW input %d (inverted)\n", k, matrixIn[n*8 + k]);
+					}
+				}
+				else {
+					if(matrixIn[n*8 + k] < 50000) {
+						dbox_printf("FAIL channel %d -- output HIGH input %d\n", k, matrixIn[n*8 + k]);
+					}
+				}
+			}
+		}
+
+		if(++sampleCounter >= 1024) {
+			sampleCounter = 0;
+			invertChannel++;
+			if(invertChannel >= 8)
+				invertChannel = 0;
+		}
+	}
+}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/sensors.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,642 @@
+/*
+ * sensors.cpp
+ *
+ *  Created on: May 28, 2014
+ *      Author: Victor Zappi
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <math.h>
+#include <vector>
+#include "prio.h"
+#include "sensors.h"
+#include "OscillatorBank.h"
+#include "DboxSensors.h"
+
+
+//----------------------------------------
+// main extern variables
+//----------------------------------------
+extern vector<OscillatorBank*> gOscBanks;
+extern int gCurrentOscBank;
+extern int gNextOscBank;
+extern bool gShouldStop;
+extern int gVerbose;
+
+float gSensor0LatestTouchPos = 0;	// most recent pitch touch location [0-1] on sensor 0, used by render.cpp
+int gSensor0LatestTouchNum	 = 0;	// most recent num of touches on sensor 0, used by render.cpp
+float gSensor1LatestTouchPos[5];	// most recent touche locations on sensor 1, used by render.cpp
+//float gSensor1LatestTouchSizes[5];
+int gSensor1LatestTouchCount;		// most recent number touches on sensor 1, used by render.cpp
+int gSensor1LatestTouchIndex = 0;	// index of last touch in gSensor1LatestTouchPos[5], used by render.cpp
+int gLastFSRValue = 1799;			// most recent fsr value, used by render.cpp
+
+
+DboxSensors Sensors;
+
+
+//----------------------------------------
+// var shared with logger
+//----------------------------------------
+int s0TouchNum	 	= 0;
+float s0Touches_[MAX_TOUCHES];
+float s0Size_[MAX_TOUCHES];
+int s0LastIndex;
+
+int s1TouchNum	 	= 0;
+float s1Touches_[MAX_TOUCHES];
+float s1Size_[MAX_TOUCHES];
+int s1LastIndex;
+
+int fsr				= 1799;
+
+
+
+using namespace std;
+
+int initSensorLoop(int sensorAddress0, int sensorAddress1, bool useNewSensors)
+{
+	int tk0_bus			= 1;
+	int tk0_address		= sensorAddress0;
+	int tk1_bus			= 1;
+	int tk1_address		= sensorAddress1;
+	int tk_file			= 0;
+	int fsr_max			= 1799;
+	int fsr_pinNum		= 4;
+
+	if(gVerbose==1)
+		cout << "---------------->Init Control Thread" << endl;
+
+	if(Sensors.initSensors(tk0_bus, tk0_address, tk1_bus, tk1_address, tk_file, fsr_pinNum, fsr_max, useNewSensors)>0)
+	{
+		gShouldStop = 1;
+		cout << "control cannot start" << endl;
+		return -1;
+	}
+
+	for(int i=0; i<MAX_TOUCHES; i++)
+	{
+		s0Touches_[i]	= 0.0;
+		s0Size_[i]		= 0.0;
+
+		s1Touches_[i]	= 0.0;
+		s1Size_[i]	= 0.0;
+	}
+
+	return 0;
+}
+
+void sensorLoop(void *)
+{
+	timeval start, end;
+	unsigned long elapsedTime;
+	//float touchSize		= 0;	// once used for timbre
+
+
+
+	float *s0Touches;
+	float *s0Size;
+	int s0PrevTouchNum 	= 0;
+	int s0SortedTouchIndices[MAX_TOUCHES];
+	float s0SortedTouches[MAX_TOUCHES];
+	float s0PrevSortedTouches[MAX_TOUCHES];
+
+	float *s1Touches;
+	float *s1Size;
+	int s1PrevTouchNum 	= 0;
+	int s1SortedTouchIndices[MAX_TOUCHES];
+	float s1SortedTouches[MAX_TOUCHES];
+	float s1PrevSortedTouches[MAX_TOUCHES];
+
+	float freqScaler	= 0;
+	int fsrMin			= 0;//50; // was 200
+	int fsrMax			= 1799;//1300; // was 800
+	float vel			= 0;
+	float prevVel		= 0;
+	float filterMaxF	= 0;
+	if(gVerbose==1)
+		dbox_printf("__________set Control Thread priority\n");
+
+	if(gVerbose==1)
+		dbox_printf("_________________Control Thread!\n");
+
+	// get freq scaler, cos freqs must be scaled according to the wavetable used in the oscillator bank
+	freqScaler 		= gOscBanks[gCurrentOscBank]->getFrequencyScaler();
+	filterMaxF		= gOscBanks[gCurrentOscBank]->filterMaxF;
+
+	// init time vals
+	gettimeofday(&start, NULL);
+
+	// here we go, sensor loop until the end of the application
+	while(!gShouldStop)
+	{
+		gettimeofday(&end, NULL);
+		elapsedTime = ( (end.tv_sec*1000000+end.tv_usec) - (start.tv_sec*1000000+start.tv_usec) );
+		if( elapsedTime<4000 )
+			usleep(4000-elapsedTime);
+		else
+			dbox_printf("%d\n", (int)elapsedTime); // this print happens when something's gone bad...
+
+		if(Sensors.readSensors()==0)
+		{
+			s0TouchNum	= Sensors.getTKTouchCount(0);
+			s0Touches	= Sensors.getTKXPositions(0);
+			s0Size 		= Sensors.getTKTouchSize(0);
+
+			s1TouchNum	= Sensors.getTKTouchCount(1);
+			s1Touches	= Sensors.getTKXPositions(1);
+			s1Size 		= Sensors.getTKTouchSize(1);
+
+			for(int i=0; i<MAX_TOUCHES; i++)
+			{
+				s0Touches_[i]	= s0Touches[i];
+				s0Size_[i]		= s0Size[i];
+
+				s1Touches_[i]	= s1Touches[i];
+				s1Size_[i]		= s1Size[i];
+			}
+
+			gSensor0LatestTouchNum	= s0TouchNum;
+			if(s0TouchNum > 0)
+			{
+				//-----------------------------------------------------------------------------------
+				// timbre, speed and  pitch
+				//touchSize	 = 0;	\\ once used for timbre
+
+				// if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison]
+				if(s0PrevTouchNum!=s0TouchNum)
+				{
+					float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches
+					int ids[MAX_TOUCHES*(MAX_TOUCHES-1)];
+					// calculate all distance permutations between previous and current touches
+					for(int i=0; i<s0TouchNum; i++)
+					{
+						for(int p=0; p<s0PrevTouchNum; p++)
+						{
+							int index			= i*s0PrevTouchNum+p;	// permutation id [says between which touches we are calculating distance]
+							distances[index]	= fabs(s0Touches[i]-s0PrevSortedTouches[p]);
+							ids[index]			= index;
+							if(index>0)
+							{
+								// sort, from min to max distance
+								float tmp;
+								while(distances[index]<distances[index-1])
+								{
+									tmp				= ids[index-1];
+									ids[index-1]	= ids[index];
+									ids[index]		= tmp;
+
+									tmp				= distances[index-1];
+									distances[index-1] = distances[index];
+									distances[index] = tmp;
+
+									index--;
+
+									if(index == 0)
+										break;
+								}
+							}
+						}
+					}
+
+					int sorted = 0;
+					bool currAssigned[MAX_TOUCHES] = {false};
+					bool prevAssigned[MAX_TOUCHES] = {false};
+
+					// track touches assigning index according to shortest distance
+					for(int i=0; i<s0TouchNum*s0PrevTouchNum; i++)
+					{
+						int currentIndex	= ids[i]/s0PrevTouchNum;
+						int prevIndex		= ids[i]%s0PrevTouchNum;
+						// avoid double assignment
+						if(!currAssigned[currentIndex] && !prevAssigned[prevIndex])
+						{
+							currAssigned[currentIndex]	= true;
+							prevAssigned[prevIndex]		= true;
+							s0SortedTouchIndices[currentIndex] = prevIndex;
+							sorted++;
+						}
+					}
+					// we still have to assign a free index to new touches
+					if(s0PrevTouchNum<s0TouchNum)
+					{
+						for(int i=0; i<s0TouchNum; i++)
+						{
+							if(!currAssigned[i])
+								s0SortedTouchIndices[i] = sorted++; // assign next free index
+
+							// update tracked value
+							s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i];
+							s0PrevSortedTouches[i]			         = s0SortedTouches[i];
+							if(s0SortedTouchIndices[i]==s0TouchNum-1)
+								s0LastIndex = i;
+
+							// accumulate sizes for timbre
+							//touchSize += s0Size[i];
+						}
+					}
+					else // some touches have disappeared...
+					{
+						// ...we have to shift all indices...
+						for(int i=s0PrevTouchNum-1; i>=0; i--)
+						{
+							if(!prevAssigned[i])
+							{
+								for(int j=0; j<s0TouchNum; j++)
+								{
+									// ...only if touches that disappeared were before the current one
+									if(s0SortedTouchIndices[j]>i)
+										s0SortedTouchIndices[j]--;
+								}
+							}
+						}
+						// done! now update
+						for(int i=0; i<s0TouchNum; i++)
+						{
+							// update tracked value
+							s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i];
+							s0PrevSortedTouches[i]			         = s0SortedTouches[i];
+							if(s0SortedTouchIndices[i]==s0TouchNum-1)
+								s0LastIndex = i;
+
+							// accumulate sizes for timbre
+							//touchSize += s0Size[i];
+						}
+					}
+				}
+				else // nothing's changed since last round
+				{
+					for(int i=0; i<s0TouchNum; i++)
+					{
+						// update tracked value
+						s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i];
+						s0PrevSortedTouches[i]			         = s0SortedTouches[i];
+
+						// accumulate sizes for timbre
+						//touchSize += s0Size[i];
+					}
+				}
+
+				if(s0TouchNum == 0)
+					s0LastIndex = -1;
+
+				// timbre
+				//touchSize = (touchSize > 0.7) ? 1 : touchSize/0.7;
+				//gOscBanks[gCurrentOscBank]->hopNumTh = log((1-touchSize)+1)/log(2)*20000;
+				//gOscBanks[gCurrentOscBank]->hopNumTh = 0;
+
+
+				// pitch, controlled by last touch
+				//prevTouchPos 				= touch[touchIndex];
+				//touchPos	 			 	= (s0SortedTouches[s0TouchNum-1]-0.5)/0.5;	// from [0,1] to [-1,1]
+				gSensor0LatestTouchPos      = s0SortedTouches[s0TouchNum-1];
+				//touchPos					= s0Touches[0];
+				//gOscBanks[gCurrentOscBank]->pitchMultiplier 	= pow(2, touchPos);
+				//-----------------------------------------------------------------------------------
+
+
+
+				//-----------------------------------------------------------------------------------
+				// note on
+				//if(s0PrevTouchNum == 0)
+				//	gOscBanks[gCurrentOscBank]->play();
+				// fsr = Sensors.getFSRVAlue();
+				fsr = gLastFSRValue;
+				//dbox_printf("fsr: %d\n", fsr);
+				if(!gOscBanks[gCurrentOscBank]->note)
+				{
+					vel = fsr;
+					vel /= (float)(fsrMax-fsrMin);
+
+					vel = 1-vel;
+					dbox_printf("Attack vel: %f\n", vel);
+					gOscBanks[gCurrentOscBank]->play(vel);
+					prevVel = vel;
+				}
+				else if(gOscBanks[gCurrentOscBank]->getEnvelopeState() != env_release)
+				{
+					fsr = (fsr > fsrMax) ? fsrMax : fsr;
+					vel = (fsr < fsrMin) ? fsrMin : fsr;
+					vel -= fsrMin;
+					vel /= (float)(fsrMax-fsrMin);
+					vel = 1-vel;
+					if(vel > prevVel)
+					{
+						gOscBanks[gCurrentOscBank]->afterTouch(vel);
+						prevVel = vel;
+					}
+				}
+				//-----------------------------------------------------------------------------------
+			}
+			else
+			{
+				//prevFsr = 1799;
+				//prevTouchPos = -1;
+				//-----------------------------------------------------------------------------------
+				// note off
+				if(s0PrevTouchNum > 0)
+				{
+					if(gOscBanks[gCurrentOscBank]->state==bank_playing)
+						gOscBanks[gCurrentOscBank]->stop();
+				}
+				//-----------------------------------------------------------------------------------
+			}
+
+
+
+			// sensor 2
+			//-----------------------------------------------------------------------------------
+			//filter - calculated even when no touches on first sensor, to filter also release tail
+			gOscBanks[gCurrentOscBank]->filterNum	= s1TouchNum;
+
+			gSensor1LatestTouchCount = gOscBanks[gCurrentOscBank]->filterNum;
+			for(int i = 0; i < gSensor1LatestTouchCount; i++) {
+				gSensor1LatestTouchPos[i] = s1Touches[i];
+				//gSensor1LatestTouchSizes[i] = s1Size[i];
+			}
+
+/*			for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++)
+			{
+				// touch pos is linear but freqs are log
+				gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((exp(s0Touches[i]*4)-1)/(exp(4)-1))*filterMaxF*freqScaler;
+				//gOscBanks[gCurrentOscBank]->filterQ[i] = size[i]*5*(1+touch[i]*1000)*freqScaler;
+				gOscBanks[gCurrentOscBank]->filterQ[i] = s0Size[i];
+				if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler)
+					gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(filterMaxF-500)*freqScaler );
+				else
+					gOscBanks[gCurrentOscBank]->filterPadding[i] = 1;
+			}*/
+
+			// each touch on sensor 2 is a notch filter, whose Q is determined by touch size
+			for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++)
+			{
+				// map touch pos [which is linear] on freqs exponentially
+				float freq = ((exp(s1Touches[i]*4)-1)/EXP_DENOM)*filterMaxF;
+				gOscBanks[gCurrentOscBank]->filterFreqs[i] = freq*freqScaler;
+				// also size is mapped exponentially on Q
+				float siz = (exp(s1Size[i])-1)/1.71828;
+				gOscBanks[gCurrentOscBank]->filterQ[i] = siz*( (filterMaxF-freq)/filterMaxF * 0.9 + 0.1 );	// size weight on Q decreases with frequency
+			}
+			//-----------------------------------------------------------------------------------
+
+
+
+			//-----------------------------------------------------------------------------------
+			// sort touches on sensor 2
+			if(s1TouchNum > 0)
+			{
+				// if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison]
+				if(s1PrevTouchNum!=s1TouchNum)
+				{
+					float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches
+					int ids[MAX_TOUCHES*(MAX_TOUCHES-1)];
+					// calculate all distance permutations between previous and current touches
+					for(int i=0; i<s1TouchNum; i++)
+					{
+						for(int p=0; p<s1PrevTouchNum; p++)
+						{
+							int index 			= i*s1PrevTouchNum+p;	// permutation id [says between which touches we are calculating distance]
+							distances[index]	= fabs(s1Touches[i]-s1PrevSortedTouches[p]);
+							ids[index]			= index;
+							if(index>0)
+							{
+								// sort, from min to max distance
+								float tmp;
+								while(distances[index]<distances[index-1])
+								{
+									tmp 				= ids[index-1];
+									ids[index-1] 		= ids[index];
+									ids[index] 			= tmp;
+
+									tmp					= distances[index-1];
+									distances[index-1]	= distances[index];
+									distances[index] 	= tmp;
+
+									index--;
+
+									if(index == 0)
+										break;
+								}
+							}
+						}
+					}
+
+					int sorted = 0;
+					bool currAssigned[MAX_TOUCHES] = {false};
+					bool prevAssigned[MAX_TOUCHES] = {false};
+
+					// track touches assigning index according to shortest distance
+					for(int i=0; i<s1TouchNum*s1PrevTouchNum; i++)
+					{
+						int currentIndex	= ids[i]/s1PrevTouchNum;
+						int prevIndex		= ids[i]%s1PrevTouchNum;
+						// avoid double assignment
+						if(!currAssigned[currentIndex] && !prevAssigned[prevIndex])
+						{
+							currAssigned[currentIndex]			= true;
+							prevAssigned[prevIndex]				= true;
+							s1SortedTouchIndices[currentIndex] = prevIndex;
+							sorted++;
+						}
+					}
+					// we still have to assign a free index to new touches
+					if(s1PrevTouchNum<s1TouchNum)
+					{
+						for(int i=0; i<s1TouchNum; i++)
+						{
+							if(!currAssigned[i])
+								s1SortedTouchIndices[i] = sorted++; // assign next free index
+
+							// update tracked value
+							s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i];
+							s1PrevSortedTouches[i]			       	 = s1SortedTouches[i];
+							if(s1SortedTouchIndices[i]==s1TouchNum-1)
+								s1LastIndex = i;
+						}
+					}
+					else // some touches have disappeared...
+					{
+						// ...we have to shift all indices...
+						for(int i=s1PrevTouchNum-1; i>=0; i--)
+						{
+							if(!prevAssigned[i])
+							{
+								for(int j=0; j<s1TouchNum; j++)
+								{
+									// ...only if touches that disappeared were before the current one
+									if(s1SortedTouchIndices[j]>i)
+										s1SortedTouchIndices[j]--;
+								}
+							}
+						}
+						// done! now update
+						for(int i=0; i<s1TouchNum; i++)
+						{
+							// update tracked value
+							s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i];
+							s1PrevSortedTouches[i]			       	 = s1SortedTouches[i];
+							if(s1SortedTouchIndices[i]==s1TouchNum-1)
+								s1LastIndex = i;
+						}
+					}
+				}
+				else // nothing's changed since last round
+				{
+					for(int i=0; i<s1TouchNum; i++)
+					{
+						// update tracked value
+						s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i];
+						s1PrevSortedTouches[i]			       	 = s1SortedTouches[i];
+					}
+				}
+			}
+
+			if(s1TouchNum > 0)
+			{
+				gSensor1LatestTouchIndex = s1LastIndex;
+			}
+			else
+				s1LastIndex = -1;
+
+/*			dbox_printf("-----------------------------\nnum: %d, latest: %d\n", s1TouchNum, gSensor1LatestTouchIndex);
+			for(int i=0; i<s1TouchNum; i++)
+				dbox_printf("\t%f\n", gSensor1LatestTouchPos[i]);
+			dbox_printf("------\n");
+			for(int i=0; i<s1TouchNum; i++)
+				dbox_printf("\t%f\n", s1SortedTouches[i]);*/
+
+
+
+			// update variables for both sensors
+			s0PrevTouchNum	= s0TouchNum;
+			s1PrevTouchNum	= s1TouchNum;
+		}
+		else
+			dbox_printf("Come on instrument!\n");	//break
+
+		gettimeofday(&start, NULL);
+	}
+
+	dbox_printf("sensor thread ended\n");
+}
+
+void *keyboardLoop(void *)
+{
+	if(gVerbose==1)
+		cout << "_________________Keyboard Control Thread!" << endl;
+
+	char keyStroke = '.';
+	cout << "Press q to quit." << endl;
+
+	float speed;
+
+	do
+	{
+		keyStroke =	getchar();
+		while(getchar()!='\n'); // to read the first stroke
+
+		switch (keyStroke)
+		{
+			//----------------------------------------------------------------------------
+			case 'a':
+				gOscBanks[gCurrentOscBank]->hopNumTh = 0;
+				gOscBanks[gCurrentOscBank]->play(1);
+				//cout << "Note on" << endl;
+				break;
+			case 's':
+				if(gOscBanks[gCurrentOscBank]->state==bank_playing)
+				{
+					gOscBanks[gCurrentOscBank]->stop();
+					//cout << "Note off" << endl;
+				}
+				break;
+			//----------------------------------------------------------------------------
+			case '[':
+				gOscBanks[gCurrentOscBank]->freqMovement-=0.05;
+				if(gOscBanks[gCurrentOscBank]->freqMovement<0)
+					gOscBanks[gCurrentOscBank]->freqMovement = 0;
+				//cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl;
+				break;
+			case ']':
+				gOscBanks[gCurrentOscBank]->freqMovement+=0.05;
+				if(gOscBanks[gCurrentOscBank]->freqMovement>1)
+					gOscBanks[gCurrentOscBank]->freqMovement = 1;
+				//cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl;
+				break;
+			//----------------------------------------------------------------------------
+			case '<':
+				speed = gOscBanks[gCurrentOscBank]->getSpeed() - 0.1 ;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+
+				break;
+			case '>':
+				speed = gOscBanks[gCurrentOscBank]->getSpeed() + 0.1 ;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+				break;
+			case '0':
+				speed = 0.1;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+				break;
+			case '1':
+				speed = 0.5;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+				break;
+			case '2':
+				speed = 1;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+				break;
+			case '3':
+				speed = 2;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+				break;
+			case '4':
+				speed = 3;
+				gOscBanks[gCurrentOscBank]->setSpeed(speed);
+				dbox_printf("Speed: %f\n", speed);
+				break;
+			//----------------------------------------------------------------------------
+			case 'z':
+				gOscBanks[gCurrentOscBank]->setJumpHop(0);
+				break;
+			case 'x':
+				gOscBanks[gCurrentOscBank]->setJumpHop(100);
+				break;
+			case 'c':
+				gOscBanks[gCurrentOscBank]->setJumpHop(600);
+				break;
+			case 'v':
+				gOscBanks[gCurrentOscBank]->setJumpHop(1100);
+				break;
+			case 'b':
+				gOscBanks[gCurrentOscBank]->setJumpHop(2000);
+				break;
+			case 'n':
+				gOscBanks[gCurrentOscBank]->setJumpHop(gOscBanks[gCurrentOscBank]->getLastHop());
+				break;
+			//----------------------------------------------------------------------------
+			case 'q':
+				gShouldStop = true;
+				break;
+			case 'o':
+				gNextOscBank = (gCurrentOscBank + 1) % gOscBanks.size();
+				break;
+			default:
+				break;
+			//----------------------------------------------------------------------------
+		}
+		usleep(1000); /* Wait 1ms to avoid checking too quickly */
+	}
+	while (keyStroke!='q');
+
+	cout << "keyboard thread ended" << endl;
+
+	return (void *)0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/sensors.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,19 @@
+/*
+ * sensors.h
+ *
+ *  Created on: May 28, 2014
+ *      Author: Victor Zappi
+ */
+
+#ifndef SENSORS_H_
+#define SENSORS_H_
+
+#include "config.h"
+
+int initSensorLoop(int sensorAddress0, int sensorAddress1, bool useNewSensors);
+
+void sensorLoop(void *);
+void *keyboardLoop(void *);
+
+
+#endif /* SENSORS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/spear_parser.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,641 @@
+/*
+ * spear_parser.cpp v1.2
+ *
+ *  Created on: May 6, 2014
+ *      Author: Victor Zappi
+ */
+
+#include "spear_parser.h"
+
+using namespace std;
+
+//#define DO_CHECKS
+
+//------------------------------------------------------------------------------------------------
+// partials
+//------------------------------------------------------------------------------------------------
+
+Partials::Partials()
+{
+	partialFrequencies	= NULL;
+//	partialAmplitudes	= NULL;
+//	partialNumFrames	= NULL;
+//	partialStartSample	= NULL;
+//	partialEndSample	= NULL;
+//	partialCurrentFrame	= NULL;
+//	partialFreqDelta	= NULL;
+//	partialAmpDelta	= NULL;
+
+
+	activePartialNum	= NULL;
+//	activePartials		= NULL;
+
+	currentSample = -1;
+}
+
+Partials::~Partials()
+{
+	if(partialFrequencies != NULL)			// check on one is enough
+	{
+		if(partialFrequencies[0] != NULL)	// check on one is enough
+		{
+			for(unsigned int i=0; i<parNum; i++)
+			{
+				delete[] partialFrequencies[i];
+				delete[] partialAmplitudes[i];
+				delete[] partialFreqDelta[i];
+				delete[] partialAmpDelta[i];
+
+			}
+		}
+
+		delete[] partialFrequencies;
+		delete[] partialAmplitudes;
+		delete[] partialNumFrames;
+		delete[] partialFreqDelta;
+		delete[] partialAmpDelta;
+		delete[] partialFreqMean;
+	}
+
+	if(activePartialNum != NULL)
+	{
+		for(unsigned int i=0; i<hopNum+1; i++)
+			delete[] activePartials[i];
+
+		delete[] activePartialNum;
+		delete[] activePartials ;
+	}
+}
+
+void Partials::init(int parN, int hopS, bool isDBX)
+{
+	if(!isDBX)
+	{
+		parNum	= parN;
+		hopSize	= hopS;
+
+		partialFrequencies	= new float *[parNum];
+		partialAmplitudes	= new float *[parNum];
+		partialNumFrames	= new unsigned int[parNum];
+		partialStartFrame	= new unsigned int[parNum];
+		partialStartSample	= new unsigned int[parNum];
+		partialEndSample	= new unsigned int[parNum];
+		partialFreqDelta	= new float *[parNum];
+		partialAmpDelta		= new float *[parNum];
+		partialFreqMean		= new float[parNum];
+
+
+
+		// init in one shot
+		fill(partialFreqMean, partialFreqMean+parNum, 0);			// mean is zero
+
+		partialFrequencies[0] 	= NULL;								// for free check
+	}
+	else
+	{
+		parNum	= parN;
+		hopSize	= hopS;
+
+		partialFrequencies	= new float *[parNum];
+		partialAmplitudes	= new float *[parNum];
+		partialNumFrames	= new unsigned int[parNum];
+		partialStartFrame	= new unsigned int[parNum];
+		partialFreqDelta	= new float *[parNum];
+		partialAmpDelta		= new float *[parNum];
+		partialFreqMean		= new float[parNum];
+
+		partialFrequencies[0] 	= NULL;								// for free check
+	}
+}
+
+
+
+void Partials::update(int parIndex, int frameNum)
+{
+	partialFrequencies[parIndex] = new float[frameNum];
+	partialAmplitudes[parIndex]	 = new float[frameNum];
+	partialFreqDelta[parIndex]	 = new float[frameNum];
+	partialAmpDelta[parIndex]	 = new float[frameNum];
+
+	fill(partialFreqDelta[parIndex], partialFreqDelta[parIndex]+frameNum, 99999.0);	// in the end, only the last one will have 99999
+	fill(partialAmpDelta[parIndex], partialAmpDelta[parIndex]+frameNum, 99999.0);	// in the end, only the last one will have 99999
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------------------------
+// spear parser
+//------------------------------------------------------------------------------------------------
+Spear_parser::Spear_parser()
+{
+	// some default values
+	hopSize			= -1;
+	fileSampleRate	= -1;
+}
+
+Spear_parser::~Spear_parser()
+{
+}
+
+void Spear_parser::calculateHopSize(char *filename)
+{
+	int index 		= 0;
+	bool prevWas_ 	= false;
+	bool found_h	= false;
+	int n 			= 0;
+
+	hopSize 		= 0;
+
+	do
+	{
+		// check if '_'
+		if(filename[index] == '_')
+			prevWas_ = true;
+		else if( (filename[index] == 'h') && prevWas_) // if it is not, but it is 'h' and previous was '_', found "_h"!
+		{
+			found_h = true;
+			while(filename[index] != '\0')
+			{
+				index++;
+				if( (filename[index] == '.') || (filename[index] == '_'))
+					break;
+				else // i am not checking if char are digits...!
+				{
+					n = filename[index];
+					hopSize =  hopSize*10+(n-48);
+				}
+			}
+		}
+		else	// else, nothing
+			prevWas_ = false;
+		index++;
+	}
+	while( (filename[index] != '\0') && !found_h );
+
+	if( !found_h || (hopSize<1) )
+		hopSize = 551;	// default val
+
+}
+
+
+bool Spear_parser::parser(char *filename, int hopsize, int samplerate)
+{
+	string name = string(filename);
+	int len		= name.length();
+	// invoke correct parser according to the type of file...just checking the extension, crude but functional
+	if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') )
+		return DBXparser(filename, samplerate);				// .dbox
+	else
+		return TXTparser(filename, hopSize, samplerate);	// .txt, or whatever
+}
+
+
+bool Spear_parser::DBXparser(char *filename, int samplerate)
+{
+	fileSampleRate 	= samplerate;
+
+	// working vars
+	int parNum		= 0;	// total num of partials
+	int hopNum		= 0;	// total num of hops
+
+	//----------------------------------------------------------------------------------------
+	// open a file
+	ifstream fin;
+	fin.open(filename, ios::in | ios::binary);
+	if (!fin.good())
+	{
+		cout << "Parser Error: file not found" << endl;	// exit if file not found
+		return false;
+	}
+
+	gettimeofday(&start, NULL);
+	//----------------------------------------------------------------------------------------
+	// general data
+
+	// look for partial count
+	fin.read((char *) &parNum, sizeof(int));
+	partials.parNum 		= parNum;
+
+	// look for hop count
+	fin.read((char *) &hopNum, sizeof(int));
+	partials.setHopNum(hopNum);
+
+	// look for hop size
+	fin.read((char *) &hopSize, sizeof(int));
+	partials.hopSize 		= hopSize;		// it's handy for both classes to know it
+
+	// init partials data structure
+	partials.init(parNum, hopSize, true);
+
+	// look for max active par num
+	fin.read((char *) &(partials.maxActiveParNum), sizeof(int));
+
+
+
+	// partial data
+
+	// start frame of each partial
+	fin.read((char *) partials.partialStartFrame, sizeof(int)*parNum);
+
+	// num of frames of each partial
+	fin.read((char *) partials.partialNumFrames, sizeof(int)*parNum);
+
+	// frequency mean of each partial
+	fin.read((char *) partials.partialFreqMean, sizeof(int)*parNum);
+
+	for(int par=0; par<parNum; par++)
+	{
+		int frameNum = partials.partialNumFrames[par];
+		partials.update(par, frameNum);
+		fin.read((char *)partials.partialAmplitudes[par], sizeof(float)*frameNum);		// amplitude of each partial in each frame
+		fin.read((char *)partials.partialFrequencies[par], sizeof(float)*frameNum);		// frequency of each partial in each frame
+		fin.read((char *)partials.partialAmpDelta[par], sizeof(float)*frameNum);			// amplitude delta of each partial in each frame
+		fin.read((char *)partials.partialFreqDelta[par], sizeof(float)*frameNum);			// frequency delta of each partial in each frame
+	}
+
+
+
+
+	// frame data
+
+	// number of active partial per each frame
+	fin.read((char *) partials.activePartialNum, sizeof(short)*(hopNum+1));
+	// init array
+	for(int frame=0; frame<hopNum+1; frame++)
+	{
+		partials.activePartials[frame] = new unsigned int[partials.activePartialNum[frame]];
+		fin.read((char *)partials.activePartials[frame], sizeof(int)*partials.activePartialNum[frame]);			// active partials per each frame
+	}
+
+
+
+
+
+	gettimeofday(&stop, NULL);
+	parserT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) );
+
+
+	printf("\n-----------------------\n");
+	printf("\nFile: %s\n", filename);
+	printf("\n-----------------------\n");
+	printf("Profiler\n");
+	printf("-----------------------\n");
+	printf("File parser:\t\t\t%lu usec\n", parserT);
+	printf("\n\nTotal:\t\t%lu usec\n", parserT);
+	printf("-----------------------\n");
+
+	fin.close();
+
+	return true;
+}
+
+
+
+
+bool Spear_parser::TXTparser(char *filename, int hopsize, int samplerate)
+{
+	hopSize 		= hopsize;
+	fileSampleRate 	= samplerate;
+	if(hopsize<0)
+	{
+		gettimeofday(&start, NULL);
+		calculateHopSize(filename);
+		gettimeofday(&stop, NULL);
+		hopSizeT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) );
+	}
+	else
+		hopSizeT = 0;
+
+	calculateDeltaTime();
+
+	// working vars
+	char * token;			// where to save single figures from file
+	string s		= "";	// where to save lines from file
+	int parNum		= 0;	// total num of partials
+	int parIndex	= -1;	// index of current partial
+	int frameNum	= 0;	// total num of frames
+	int frameIndex	= -1;	// index of current frame
+	int startSample	= -1;	// sample value for first frame of partials
+	int endSample	= -1;	// sample value for last frame of partials
+	int maxSample	= 0;	// to calculate total number of hops in file
+	int missSampCnt = 0;	// number of mising samples
+	double freq		= 0;	// to calculate frequency delta
+	double prevFreq	= 0;	// to calculate frequency delta
+	double amp		= 0;	// to calculate amplitude delta
+	double prevAmp	= 0;	// to calculate amplitude delta
+
+
+	//----------------------------------------------------------------------------------------
+	// open a file
+	ifstream fin;
+	fin.open(filename);
+	if (!fin.good())
+	{
+		cout << "Parser Error: file not found" << endl;	// exit if file not found
+		return false;
+	}
+
+	gettimeofday(&start, NULL);
+	//----------------------------------------------------------------------------------------
+	// init partials data structure
+	getline(fin, s);
+	getline(fin, s);
+	getline(fin, s);	// third line is the first we are interested into
+
+	// look for partial count
+	token = strtok((char *)s.c_str(), " ");
+	// check if first token is there
+	if(token)
+	{
+		token = strtok(0, " ");
+		// check if second token is there
+		if(token)
+			parNum = atoi(token);
+		#ifdef DO_CHECKS
+		else
+		{
+			cout << "Parser Error: partial count not found, bad file format" << endl;	// exit if value not found
+			return false;
+		}
+		#endif
+	}
+	#ifdef DO_CHECKS
+	else
+	{
+		cout << "Parser Error: partial count not found, bad file format" << endl;		// exit if value not found
+		return false;
+	}
+	#endif
+	// from now on we take for granted that format is correct
+
+	// init partials data structure
+	partials.init(parNum, hopSize);
+
+	//----------------------------------------------------------------------------------------
+	// fill in partials data structure
+	getline(fin, s);		// get rid of intro line "partials-data"
+	getline(fin, s);		// first important line
+
+	while (!fin.eof())
+	{
+		//-------------------------------------
+		// partial specific info
+		token		= strtok((char *)s.c_str(), " ");
+		parIndex	= atoi(token);						// partial index
+
+		token		= strtok(0, " ");					// num of frames, not used, cos we will do linear interpolation for missing frames
+//		frameNum	= atoi(token);
+//		partials.partialNumFrames[parIndex]	= frameNum;
+
+		token		= strtok(0, " ");					// time of first frame, still char *
+		startSample = fromTimeToSamples(atof(token));	// convert time to samples
+		partials.partialStartSample[parIndex]	= startSample;
+
+		token		= strtok(0, " ");					// time of last frame, still char *
+		endSample	= fromTimeToSamples(atof(token)); 	// convert time to samples
+		partials.partialEndSample[parIndex]		= endSample;
+
+		frameNum	= ((endSample-startSample)/hopSize) + 1;	// num of frames, including missing consecutive ones [+1 one cos we count frames, not hops]
+		partials.partialNumFrames[parIndex]		= frameNum;
+
+
+		// check if this is the highest sample value so far
+		if(endSample > maxSample)
+			maxSample = endSample;
+
+		// update data structure
+		partials.update(parIndex, frameNum);
+
+
+		//-------------------------------------
+		// frames
+		getline(fin, s);
+		token		= strtok((char *)s.c_str(), " ");	// frame time
+		frameIndex	= -1;
+
+		// unroll first iteration, so that in the following loop we save the check on the last frame to calculate increments
+		if(token)						// all frames data are on one line, in groups of 3 entries
+		{
+			frameIndex++;
+
+			endSample	= fromTimeToSamples(atof(token));
+
+			token		= strtok(0, " ");	// frame frequency
+			prevFreq	= atof(token);
+			partials.partialFrequencies[parIndex][frameIndex]	= (float)prevFreq;
+			partials.partialFreqMean[parIndex] 					+= prevFreq;		// for frequency mean
+
+			token	 	= strtok(0, " ");	// frame amplitude
+			prevAmp  	= atof(token);
+			partials.partialAmplitudes[parIndex][frameIndex]	= (float)prevAmp;
+
+			token 		= strtok(0, " ");	// next frame frequency, to be checked
+		}
+
+		// here the loop starts
+		while(token)						// all frames data are on one line, in groups of 3 entries
+		{
+			frameIndex++;
+			missSampCnt 	= 0;
+
+			startSample		= fromTimeToSamples(atof(token));
+
+			token			= strtok(0, " ");	// frame frequency
+			freq			= atof(token);
+
+			token			= strtok(0, " ");	// frame amplitude
+			amp				= atof(token);
+			// now we know all about the current frame, but we want to know if some frames are missing between this and the last one
+
+			// while current frame sample is farther than one hopsize...
+			while(startSample > endSample+hopSize)
+			{
+				missSampCnt++;				// ...one sample is missing
+				endSample += hopSize;		// move to next hop
+			}
+
+			// if frames are missing do interpolation and update indices
+			if(missSampCnt>0)
+				startSample = interpolateSamples(parIndex, &frameIndex, missSampCnt, endSample+hopSize, freq, amp, &prevFreq, &prevAmp);
+
+			partials.partialFrequencies[parIndex][frameIndex]	= (float)freq;
+			partials.partialFreqMean[parIndex] 					+= freq;			// for frequency mean
+			partials.setFreqDelta(parIndex, frameIndex-1, (freq-prevFreq)/hopSize);	// freq delta between prev and current frame
+			prevFreq 	= freq;
+
+			partials.partialAmplitudes[parIndex][frameIndex]	= (float)amp;
+			partials.setAmpDelta(parIndex, frameIndex-1, (amp-prevAmp)/hopSize);	// amp delta between prev and current frame
+			prevAmp		= amp;
+
+			endSample	= startSample;
+			token		= strtok(0, " ");	// next frame frequency, to be checked
+		}
+		#ifdef DO_CHECKS
+		if(frameIndex != (frameNum-1))
+		{
+			cout << "Parser Error: frame count mismatch on partial " << parIndex << ", bad file format"  << endl;	// exit if mismatch
+			cout << "frameIndex: " << frameIndex << endl;
+			cout << "frameNum: " << frameNum << endl;
+			return false;
+		}
+		#endif
+
+		partials.partialFreqMean[parIndex] /= partials.partialNumFrames[parIndex];									// frequency mean
+
+		getline(fin, s);					// next partial line, to check
+	}
+	#ifdef DO_CHECKS
+	if(parIndex != (parNum-1))
+	{
+		cout << "Parser Error: partial count mismatch, bad file format"  << endl;									// exit if mismatch
+		return false;
+	}
+	#endif
+
+	partials.setHopNum(maxSample/hopSize);
+
+	gettimeofday(&stop, NULL);
+	parserT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) );
+
+	gettimeofday(&start, NULL);
+	staticCalculations();
+	gettimeofday(&stop, NULL);
+	staticT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) );
+
+	fin.close();
+
+
+	printf("\n-----------------------\n");
+	printf("\nFile: %s\n", filename);
+	printf("\n-----------------------\n");
+	printf("Profiler\n");
+	printf("-----------------------\n");
+	printf("Hop size parser:\t\t%lu usec\n", hopSizeT);
+	printf("File parser:\t\t\t%lu usec\n", parserT);
+	printf("Static calculations:\t\t%lu usec\n", staticT);
+	printf("\n\nTotal:\t\t%lu usec\n", hopSizeT+parserT+staticT);
+	printf("-----------------------\n");
+
+	return true;
+}
+
+
+int Spear_parser::interpolateSamples(int parIndex, int *frameIndex, int missCnt, int nextSample, double nextFreq, double nextAmp, double *prevFreq, double *prevAmp)
+{
+	int frame			= *frameIndex;						// current frame index
+	int sample			= nextSample - (hopSize*(missCnt)); // move from next real frame sample to first missing frame sample
+	double freq			= *prevFreq;						// freq of the prev real frame
+	double freqStep		= (nextFreq-*prevFreq)/(missCnt+1);	// fixed freq step between hops, for missing frames [linear interpolation]
+	double deltaFreq	= freqStep/hopSize;					// fixed hop freq step in samples
+	double amp			= *prevAmp;							// same for amp...
+	double ampStep		= (nextAmp-*prevAmp)/(missCnt+1);
+	double deltaAmp		= ampStep/hopSize;
+
+	// for each missing frame
+	for(int i=0; i<missCnt; i++)
+	{
+		// calculate values for current missing frame
+		freq	+= freqStep;
+		amp		+= ampStep;
+		// save values
+		partials.partialFrequencies[parIndex][frame]	= freq;
+		partials.partialAmplitudes[parIndex][frame]		= amp;
+		partials.partialFreqMean[parIndex]				+= freq;	// for frequency mean
+		// set deltas of previous frame [real or missing]
+		partials.setFreqDelta(parIndex, frame-1, deltaFreq);
+		partials.setAmpDelta(parIndex, frame-1, deltaAmp);
+		// move to next frame [missing or real]
+		sample += hopSize;
+		frame++;
+	}
+
+	// update global values
+	*frameIndex	= frame;
+	*prevFreq	= freq;
+	*prevAmp	= amp;
+
+	return sample;	// return the frame sample of the next real frame
+}
+
+
+
+// for each frame, statically calculate:
+// - which partial is active [and the total num of active partials]
+// - at which local frame each partial is
+void Spear_parser::staticCalculations()
+{
+	partials.maxActiveParNum = 0;				// init to find maximum
+
+	unsigned short *indices	= new unsigned short[partials.parNum];	// temp array to store up to the maximum num of active partial indices
+	unsigned int activeCnt	= 0;						// counts the num of active partials in each frame
+
+	unsigned int frameSample = 0;						// current frame in samples
+
+	char *partialStarted = new char [partials.parNum];	// index of the last local frame found per each partial
+	fill(partialStarted, partialStarted+partials.parNum, 0);
+
+	for(unsigned int i=0; i<partials.hopNum+1; i++)		// for each frame [not hops, this explains the +1]
+	{
+		//partials.localPartialFrames[i] = new int[partials.parNum];	// init all local frames to -1
+		//fill(partials.localPartialFrames[i], partials.localPartialFrames[i]+partials.parNum, -1);
+
+		frameSample = i*hopSize;	// current frame, expressed in samples
+		activeCnt	  = 0;			// reset a each frame
+
+		for(unsigned int j=0; j<partials.parNum; j++)	// for each partial
+		{
+			// check if inside active time region [expressed in samples]
+			if( (frameSample>=partials.partialStartSample[j]) && (frameSample<partials.partialEndSample[j]) )	// frame sample not equal to end sample, this filters out last frames and partials with one frame only
+			{
+				// activity
+				indices[activeCnt] = j;	// save active index
+				activeCnt++;			// increase counter
+
+				// partial local frames
+				if(partialStarted[j]==0)	// this partial has just started, so current local frame is first frame
+				{
+					partialStarted[j] 		 		= 1;
+					partials.partialStartFrame[j]	= i;	// here is the number of the first frame
+				}
+			}
+		}
+
+		// activity
+		partials.activePartialNum[i] = activeCnt;							// save number of active partials for this frame
+		partials.activePartials[i]	 = new unsigned int[activeCnt];					// set correct size to save all indices
+
+		// look for maximum number of active partials at the same time
+		if(activeCnt > partials.maxActiveParNum)
+			partials.maxActiveParNum = activeCnt;
+
+		// copy indices
+		for(unsigned int k=0; k<activeCnt; k++)
+			partials.activePartials[i][k] = indices[k];
+	}
+
+	delete[] indices;
+	delete[] partialStarted;
+
+	delete[] partials.partialStartSample;
+	delete[] partials.partialEndSample;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/d-box/spear_parser.h	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,188 @@
+/*
+ * spear_parser.h v1.2
+ *
+ *  Created on: May 6, 2014
+ *      Author: Victor Zappi
+ */
+
+#ifndef SPEAR_PARSER_H_
+#define SPEAR_PARSER_H_
+
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <string>
+#include <stdlib.h>		// atoi, atof
+#include <math.h>
+#include <algorithm>	// std::fill
+
+#include <sys/time.h>
+
+using namespace std;
+
+
+//------------------------------------------------------------------------------------------------
+// partials
+//------------------------------------------------------------------------------------------------
+
+class Spear_parser; // for class friendship
+
+class Partials
+{
+	friend class Spear_parser;
+	friend class Dbox_parser;
+
+public:
+	int **partialSamples;				// sample at which each frame is
+	float **partialFrequencies;			// frequencies at each frame
+	float **partialAmplitudes;			// amplitudes at each frame
+	unsigned int *partialNumFrames;		// Length of each partial in frames
+	unsigned int *partialStartFrame;	// frame at which each partial begins
+	float **partialFreqDelta;			// constant frequency slope for each partial in each frame interval
+	float **partialAmpDelta;			// constant amplitude slope for each partial in each frame interval
+	float *partialFreqMean;				// frequency mean for each partial, over all its frames
+
+	unsigned short *activePartialNum;	// num of each active partial at each frame
+	unsigned int **activePartials;		// indices of all active partials at each frame
+
+
+	int getPartialNum();
+	int getHopNum();
+	int getMaxActivePartialNum();
+
+private:
+	Partials();
+	~Partials();
+
+	unsigned int *partialStartSample;	// sample at which each partial begins
+	unsigned int *partialEndSample;		// sample at which each partial ends [sample gap between 2 consecutive frames can be an integer multiple of hopSize]
+	unsigned int parNum;
+	unsigned int currentSample;
+	unsigned int hopSize;
+	unsigned int hopNum;
+	unsigned int maxActiveParNum;
+
+	void init(int parNum, int hopSize, bool isDBX=false);
+	void update(int parIndex, int frameNum);
+	void setFreqDelta(int parIndex, int frameNum, double delta);
+	void setAmpDelta(int parIndex, int frameNum, double delta);
+	void setHopNum(int hopNum);
+};
+
+inline int Partials::getPartialNum()
+{
+	return parNum;
+}
+
+inline void Partials::setHopNum(int hopN)
+{
+	hopNum = hopN;
+
+	// prepare data structures
+	activePartialNum 	= new unsigned short[hopNum+1];	// +1 cos total num of frames = num of hops+1
+	activePartials	 	= new unsigned int *[hopNum+1];
+}
+
+// useful to increase current sample using a modulo on the total number of samples [easy to be deduced from the total num or hops]
+inline int Partials::getHopNum()
+{
+	return hopNum;
+}
+
+inline void Partials::setFreqDelta(int parIndex, int frameNum, double delta)
+{
+	partialFreqDelta[parIndex][frameNum] = delta;
+}
+
+inline void Partials::setAmpDelta(int parIndex, int frameNum, double delta)
+{
+	partialAmpDelta[parIndex][frameNum] = delta;
+}
+
+inline int Partials::getMaxActivePartialNum()
+{
+	return maxActiveParNum;
+}
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------------------------
+// spear parser
+//------------------------------------------------------------------------------------------------
+
+class Spear_parser
+{
+public:
+	Spear_parser();
+	~Spear_parser();
+
+	Partials partials;
+
+	bool parseFile(string filename, int hopsize=-1, int samplerate = 44100);
+	bool parseFile(char *filename, int hopsize=-1, int samplerate = 44100);
+	int getHopSize();
+	int getFileSampleRate();
+	double getDeltaTime();
+
+private:
+
+	int hopSize;
+	int fileSampleRate;
+	double deltaTime;	// min time gap between consecutive frames
+
+	timeval start, stop;
+	unsigned long hopSizeT, parserT, staticT;
+
+	void calculateDeltaTime();
+	void calculateHopSize(char *filename);
+	bool parser(char *filename, int hopsize=-1, int samplerate=44100);
+	bool DBXparser(char *filename, int samplerate=44100);
+	bool TXTparser(char *filename, int hopsize=-1, int samplerate=44100);
+	int fromTimeToSamples(float time);
+	int interpolateSamples(int parIndex, int *frameIndex, int missCnt, int nextSample,
+							double nextFreq, double nextAmp, double *prevFreq, double *prevAmp);
+	void staticCalculations();
+
+};
+
+inline bool Spear_parser::parseFile(string filename, int hopsize, int samplerate)
+{
+	return parser((char *)filename.c_str(), hopsize, samplerate);
+}
+
+inline bool Spear_parser::parseFile(char *filename, int hopsize, int samplerate)
+{
+	return parser(filename, hopsize, samplerate);
+}
+
+inline void Spear_parser::calculateDeltaTime()
+{
+	deltaTime = (double)hopSize/ (double)fileSampleRate;
+}
+
+// each time value in the file is rounded, and 2 consecutive frames can differ of a time gap = i*deltaTime, where i is a positive integer
+inline int Spear_parser::fromTimeToSamples(float time)
+{
+	return round(time/deltaTime)*hopSize;	// round is necessary since in the file log time values are rounded, so they do not apparently look like integer multiples of deltaTime
+}
+
+inline int Spear_parser::getHopSize()
+{
+	return hopSize;
+}
+
+inline int Spear_parser::getFileSampleRate()
+{
+	return fileSampleRate;
+}
+
+inline double Spear_parser::getDeltaTime()
+{
+	return deltaTime;
+}
+
+#endif /* SPEAR_PARSER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/oscillator_bank/audio_routines.S	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,161 @@
+@
+@ audio_routines.S
+@
+@ NEON-based functions for time-critical audio processing
+@
+@ Andrew McPherson 2014
+@ Queen Mary University of London
+@
+
+	.syntax unified
+	.arch armv7-a
+	.fpu neon
+
+@ 	void oscillator_bank_neon(int numAudioFrames, float *audioOut,
+@							  int activePartialNum, int lookupTableSize,
+@							  float *phases, float *frequencies, float *amplitudes,
+@							  float *freqDerivatives, float *ampDerivatives,
+@							  float *lookupTable);
+
+@ Registers:
+@    r0: numAudioFrames        How many frames to render
+@    r1: audioOut              Buffer for audio output samples [stereo]
+@    r2: activePartialNum      How many active partials to render
+@    r3: lookupTableSize       Size of lookup table
+@    ---- other arguments start on the stack and are moved: -----
+@    r4: phases                Phase of each oscillator (pointer)
+@    r5: frequencies           Normalised frequency of each oscillator (pointer)
+@    r6: amplitudes            Normalised amplitude of each oscillator (pointer)
+@    r7: freqDerivatives       Derivative of frequency for each oscillator (pointer)
+@    r8: ampDerivatives        Derivative of amplitude for each oscillator (pointer)
+@    r9: lookupTable           Lookup table containing one oscillation
+@
+@ Alignment requirements:
+@    audioOut: 8-byte boundary
+@    phases: 16-byte boundary
+@    frequencies: 16-byte boundary
+@    amplitudes: 16-byte boundary
+@    freqDerivatives: 16-byte bounary
+@    ampDerivatives: 16-byte boundary
+@    lookupTable: 4-byte boundary (TODO: check this)
+
+	.align	2
+	.global	oscillator_bank_neon
+	.thumb
+	.thumb_func
+	.type	oscillator_bank_neon, %function
+oscillator_bank_neon:
+
+
+dSample		.dn		D6.F32
+qPhases		.qn		Q8.F32
+dPhases_0	.dn		D16.F32
+dPhases_1	.dn		D17.F32
+qFreqs		.qn		Q9.F32
+dFreqs_0	.dn		D18.F32
+dFreqs_1	.dn		D19.F32
+qAmps		.qn		Q10.F32
+dAmps_0		.dn		D20.F32
+dAmps_1		.dn		D21.F32
+qFreqDs		.qn		Q11.F32
+dFreqDs_0	.dn		D22.F32
+dFreqDs_1	.dn		D23.F32
+qAmpDs		.qn		Q12.F32
+dAmpDs_0	.dn		D24.F32
+dAmpDs_1	.dn		D25.F32
+
+qBaseInts	.qn		Q13.U32		@ Base indexes: unsigned ints x4
+dBaseInts_0	.dn		D26.U32
+dBaseInts_1	.dn		D27.U32
+qFractions  .qn     Q14.F32		@ Fraction indexes: floats x4
+qTableBase	.qn		Q15.U32		@ Base of lookup table
+
+	cmp r0, #0					@ Check for trivial case 1: zero frames
+	it eq
+	bxeq lr						@ Return if that's the case (otherwise might have odd behaviour)
+	cmp r2, #4					@ Check for trivial case 2: zero oscillators
+	it lt
+	bxlt lr						@ Return if that's the case
+
+	push {r4-r11}				@ Now arguments start 32 bytes above SP
+    add r11, sp, #32			@ Pointer to 32 bytes into the stack
+    ldm r11, {r4-r9}			@ Load 6 arguments into registers
+
+	vdup qTableBase, r9			@ Move lookup table base index into 4 ints
+
+	@ Outer loop: iterate over the number of oscillators, choosing 4 at a
+	@ time to work with.
+oscbank_oscillator_loop:
+	vld1 {dPhases_0, dPhases_1}, [r4]		@ no increment; will store at end of sample loop
+	vld1 {dFreqs_0, dFreqs_1}, [r5]
+	vld1 {dAmps_0, dAmps_1}, [r6]
+	vld1 {dFreqDs_0, dFreqDs_1}, [r7]!		@ increment; won't update at end of sample loop
+	vld1 {dAmpDs_0, dAmpDs_1}, [r8]!
+
+	push {r0-r1,r4-r8}
+	@ --- inner loop: iterate over the number of samples ---
+oscbank_sample_loop:
+	vcvt qBaseInts, qPhases		     		@ Take floor(phases)
+	vmov q2.f32, #1.0						@ Load 1.0 into every slot of q2
+	vshl q0.U32, qBaseInts, #2				@ Shift the indexes left 2 (*4 for float addressing)
+	vcvt qFractions, qBaseInts				@ int back to float
+	vadd q0.U32, q0.U32, qTableBase			@ Find memory addresses
+
+	vmov r4, r5, d0							@ Move two indexes to ARM registers
+	vmov r6, r7, d1							@ Move two more indexes to ARM registers
+	vsub qFractions, qPhases, qFractions	@ fraction = phase - floor(phase)
+
+	vldr.64	d0, [r4]						@ Load two consecutive floats at each location
+	vldr.64 d1, [r5]						@ These hold the previous and following samples in the table
+	vldr.64	d2, [r6]						@ TODO: check whether these work at 4-byte alignment
+	vldr.64 d3, [r7]
+
+	@ Format at this point:
+	@ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after)
+	@ We want:
+	@ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after)
+
+	vuzp.32 q0, q1							@ Now q0 contains before, q1 contains after
+	vsub q2.f32, q2.f32, qFractions			@ q2 = 1.0 - fraction
+	vmul q1.f32, q1.f32, qFractions			@ q1 = fraction * after
+	vmul q0.f32, q0.f32, q2.f32				@ q0 = (1.0 - fraction) * before
+
+	vadd qPhases, qPhases, qFreqs			@ Update phases
+	vadd qFreqs, qFreqs, qFreqDs			@ Update frequencies
+
+	vadd q0.f32, q0.f32, q1.f32				@ Add two interpolated components to get the final sample
+	vdup q2.u32, r3							@ Put lookup table size into each element of q2
+	vcvt qBaseInts, qPhases					@ Take floor of new phases
+	vmul q0.f32, q0.f32, qAmps				@ Multiply samples by current amplitude
+
+	vld1 dSample, [r1]						@ Load the current stereo samples
+	vpadd d2.f32, d0.f32, d1.f32			@ Pairwise accumulate q0 (output sample) into d2
+
+	vand q2, q2, qBaseInts					@ Logical AND of new phase int leaves 1 bit set only if phase >= table size
+	vpadd d3.f32, d2.f32, d2.f32			@ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators
+	vadd qAmps, qAmps, qAmpDs				@ Update amplitudes
+	vcvt q0.f32, q2.u32						@ Convert int back to float after AND operation
+
+	vadd  dSample, dSample, d3.f32			@ Add oscillator outputs to each channel
+
+	subs r0, r0, #1							@ numFrames--
+	vsub qPhases, qPhases, q0.f32			@ Keep phases in table range
+	vst1 dSample, [r1]!						@ Store back in buffer and increment by 8
+
+	it gt
+	bgt oscbank_sample_loop					@ Loop if numFrames > 0
+
+	@ --- end inner loop ---
+	pop {r0-r1,r4-r8}						@ Restore registers: restores audioOut and numFrames, among others
+
+	vst1 {dPhases_0, dPhases_1}, [r4]!		@ Store phases back to array
+	vst1 {dFreqs_0, dFreqs_1}, [r5]!		@ Store frequencies back to array
+	vst1 {dAmps_0, dAmps_1}, [r6]!			@ Store amplitudes back to array
+											@ No need to update r7, r8
+
+	subs r2, r2, #4							@ numPartials -= 4
+	it  gt
+	bgt oscbank_oscillator_loop	@ Loop if numPartials > 0
+
+    pop {r4-r11}
+	bx lr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/oscillator_bank/main.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,129 @@
+/*
+ * main.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <libgen.h>
+#include <signal.h>
+#include "../../include/RTAudio.h"
+
+using namespace std;
+
+int gNumOscillators = 32;
+int gWavetableLength = 1024;
+
+
+// Handle Ctrl-C by requesting that the audio rendering stop
+void interrupt_handler(int var)
+{
+	gShouldStop = true;
+}
+
+// Print usage information
+void usage(const char * processName)
+{
+	cerr << "Usage: " << processName << " [-h] [-v] [-p period] [-f input] [-a input]" << endl;
+	cerr << "   -h:           Print this menu\n";
+	cerr << "   -v:           Enable verbose messages\n";
+	cerr << "   -p period:    Set the period (hardware buffer) size in sensor frames\n";
+    cerr << "   -n oscs:      Set the number of oscillators to use (default: 32)\n";
+    cerr << "   -w length:    Set the wavetable length in samples (default: 1024)\n";
+	cerr << "   -m:           Enable the matrix (ADC and DAC) for controlling parameters\n";
+}
+
+int main(int argc, char *argv[])
+{
+	int periodSize = 8;			// Period size in sensor frames
+	int verbose = 0;			// Verbose printing level
+	int useMatrix = 0;
+
+	// Parse command-line arguments
+	while (1) {
+		int c;
+		if ((c = getopt(argc, argv, "hp:vn:w:m")) < 0)
+				break;
+		switch (c) {
+		case 'h':
+				usage(basename(argv[0]));
+				exit(0);
+		case 'p':
+				periodSize = atoi(optarg);
+				if(periodSize < 1)
+					periodSize = 1;
+				break;
+		case 'v':
+				verbose = 1;
+				break;
+		case 'n':
+				gNumOscillators = atoi(optarg);
+				if(gNumOscillators <= 0) {
+					usage(basename(argv[0]));
+					exit(0);
+				}
+				break;
+		case 'w':
+				gWavetableLength = atoi(optarg);
+				if(gWavetableLength < 4)
+					gWavetableLength = 4;
+				if(gWavetableLength > 16384)
+					gWavetableLength = 16384;
+				break;
+		case 'm':
+				useMatrix = 1;
+				break;
+		case '?':
+		default:
+				usage(basename(argv[0]));
+				exit(1);
+		}
+	}
+
+
+	// Set verbose logging information (optional by using value > 0; default is 0)
+	setVerboseLevel(verbose);
+
+	if(verbose) {
+		cout << "Starting with period size " << periodSize << endl;
+		cout << "--> Using " << gNumOscillators << " oscillators and wavetable of " << gWavetableLength << " samples\n";
+		cout << "--> Matrix ";
+		if(useMatrix) cout << "enabled\n";
+		else cout << "disabled\n";
+	}
+
+	// Initialise the PRU audio device
+	if(initAudio(periodSize, useMatrix, 0) != 0) {
+		cout << "Error: unable to initialise audio" << endl;
+		return -1;
+	}
+
+	// Start the audio device running
+	if(startAudio()) {
+		cout << "Error: unable to start real-time audio" << endl;
+		return -1;
+	}
+
+	// Set up interrupt handler to catch Control-C
+	signal(SIGINT, interrupt_handler);
+
+	// Run until told to stop
+	while(!gShouldStop) {
+		usleep(100000);
+	}
+
+	// Stop the audio device
+	stopAudio();
+
+	if(verbose) {
+		cout << "Cleaning up..." << endl;
+	}
+
+	// Clean up any resources allocated for audio
+	cleanupAudio();
+
+	// All done!
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/oscillator_bank/render.cpp	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,202 @@
+/*
+ * render.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+
+#include "../../include/RTAudio.h"
+#include "../../include/Utilities.h"
+#include <rtdk.h>
+#include <cstdlib>
+#include <cmath>
+#include <cstring>
+#include <time.h>
+
+const float kMinimumFrequency = 20.0f;
+const float kMaximumFrequency = 8000.0f;
+
+float *gWavetable;		// Buffer holding the precalculated sine lookup table
+float *gPhases;			// Buffer holding the phase of each oscillator
+float *gFrequencies;	// Buffer holding the frequencies of each oscillator
+float *gAmplitudes;		// Buffer holding the amplitudes of each oscillator
+float *gDFrequencies;	// Buffer holding the derivatives of frequency
+float *gDAmplitudes;	// Buffer holding the derivatives of amplitude
+
+float gAudioSampleRate;
+int gSampleCount;		// Sample counter for indicating when to update frequencies
+float gNewMinFrequency;
+float gNewMaxFrequency;
+
+// Task for handling the update of the frequencies using the matrix
+AuxiliaryTask gFrequencyUpdateTask;
+
+// These settings are carried over from main.cpp
+// Setting global variables is an alternative approach
+// to passing a structure to userData in initialise_render()
+
+extern int gNumOscillators;
+extern int gWavetableLength;
+
+void recalculate_frequencies();
+
+extern "C" {
+	// Function prototype for ARM assembly implementation of oscillator bank
+	void oscillator_bank_neon(int numAudioFrames, float *audioOut,
+							  int activePartialNum, int lookupTableSize,
+							  float *phases, float *frequencies, float *amplitudes,
+							  float *freqDerivatives, float *ampDerivatives,
+							  float *lookupTable);
+}
+
+// initialise_render() is called once before the audio rendering starts.
+// Use it to perform any initialisation and allocation which is dependent
+// on the period size or sample rate.
+//
+// userData holds an opaque pointer to a data structure that was passed
+// in from the call to initAudio().
+//
+// Return true on success; returning false halts the program.
+
+bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
+					   int numAudioFramesPerPeriod, float matrixSampleRate,
+					   float audioSampleRate, void *userData)
+{
+	srandom(time(NULL));
+
+	// Initialise the sine wavetable
+	if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) {
+		rt_printf("Error allocating wavetable\n");
+		return false;
+	}
+	for(int n = 0; n < gWavetableLength + 1; n++)
+		gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength);
+
+	// Allocate the other buffers
+	if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) {
+		rt_printf("Error allocating phase buffer\n");
+		return false;
+	}
+	if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) {
+		rt_printf("Error allocating frequency buffer\n");
+		return false;
+	}
+	if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) {
+		rt_printf("Error allocating amplitude buffer\n");
+		return false;
+	}
+	if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) {
+		rt_printf("Error allocating frequency derivative buffer\n");
+		return false;
+	}
+	if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) {
+		rt_printf("Error allocating amplitude derivative buffer\n");
+		return false;
+	}
+
+	// Initialise buffer contents
+
+	float freq = kMinimumFrequency;
+	float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators;
+
+	for(int n = 0; n < gNumOscillators; n++) {
+		gPhases[n] = 0.0;
+
+		if(numMatrixFramesPerPeriod == 0) {
+			// Random frequencies when used without matrix
+			gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX);
+		}
+		else {
+			// Constant spread of frequencies when used with matrix
+			gFrequencies[n] = freq;
+			freq += increment;
+		}
+
+		// For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians
+		gFrequencies[n] *= (float)gWavetableLength / audioSampleRate;
+		gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators;
+		gDFrequencies[n] = gDAmplitudes[n] = 0.0;
+	}
+
+	// Initialise auxiliary tasks
+	if((gFrequencyUpdateTask = createAuxiliaryTaskLoop(&recalculate_frequencies, 90, "beaglert-update-frequencies")) == 0)
+		return false;
+
+	gAudioSampleRate = audioSampleRate;
+	gSampleCount = 0;
+
+	return true;
+}
+
+// render() is called regularly at the highest priority by the audio engine.
+// Input and output are given from the audio hardware and the other
+// ADCs and DACs (if available). If only audio is available, numMatrixFrames
+// will be 0.
+
+void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
+			uint16_t *matrixIn, uint16_t *matrixOut)
+{
+	// Initialise buffer to 0
+	memset(audioOut, 0, 2 * numAudioFrames * sizeof(float));
+
+	// Render audio frames
+	oscillator_bank_neon(numAudioFrames, audioOut,
+			gNumOscillators, gWavetableLength,
+			gPhases, gFrequencies, gAmplitudes,
+			gDFrequencies, gDAmplitudes,
+			gWavetable);
+
+	if(numMatrixFrames != 0 && (gSampleCount += numAudioFrames) >= 128) {
+		gSampleCount = 0;
+		gNewMinFrequency = map(matrixIn[0], 0, MATRIX_MAX, 20.0f, 8000.0f);
+		gNewMaxFrequency = map(matrixIn[1], 0, MATRIX_MAX, 20.0f, 8000.0f);
+
+		// Make sure max >= min
+		if(gNewMaxFrequency < gNewMinFrequency) {
+			float temp = gNewMaxFrequency;
+			gNewMaxFrequency = gNewMinFrequency;
+			gNewMinFrequency = temp;
+		}
+
+		// Request that the lower-priority task run at next opportunity
+		scheduleAuxiliaryTask(gFrequencyUpdateTask);
+	}
+}
+
+// This is a lower-priority call to update the frequencies which will happen
+// periodically when the matrix is enabled. By placing it at a lower priority,
+// it has minimal effect on the audio performance but it will take longer to
+// complete if the system is under heavy audio load.
+
+void recalculate_frequencies()
+{
+	float freq = gNewMinFrequency;
+	float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators;
+
+	for(int n = 0; n < gNumOscillators; n++) {
+		// Update the frequencies to a regular spread, plus a small amount of randomness
+		// to avoid weird phase effects
+		float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX;
+		float newFreq = freq * randScale;
+
+		// For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians
+		gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate;
+
+		freq += increment;
+	}
+}
+
+
+// cleanup_render() is called once at the end, after the audio has stopped.
+// Release any resources that were allocated in initialise_render().
+
+void cleanup_render()
+{
+	free(gWavetable);
+	free(gPhases);
+	free(gFrequencies);
+	free(gAmplitudes);
+	free(gDFrequencies);
+	free(gDAmplitudes);
+}
Binary file pru_rtaudio.bin has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pru_rtaudio.p	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,753 @@
+.origin 0
+.entrypoint START
+
+#define DBOX_CAPE	// Define this to use new cape hardware
+	
+#define CLOCK_BASE  0x44E00000
+#define CLOCK_SPI0  0x4C
+#define CLOCK_SPI1  0x50
+#define CLOCK_L4LS  0x60
+
+#define SPI0_BASE   0x48030100
+#define SPI1_BASE   0x481A0100
+#define SPI_BASE    SPI0_BASE
+	
+#define SPI_SYSCONFIG 0x10
+#define SPI_SYSSTATUS 0x14
+#define SPI_MODULCTRL 0x28
+#define SPI_CH0CONF   0x2C
+#define SPI_CH0STAT   0x30
+#define SPI_CH0CTRL   0x34
+#define SPI_CH0TX     0x38
+#define SPI_CH0RX     0x3C
+#define SPI_CH1CONF   0x40
+#define SPI_CH1STAT   0x44
+#define SPI_CH1CTRL   0x48
+#define SPI_CH1TX     0x4C
+#define SPI_CH1RX     0x50
+
+#define GPIO0 0x44E07000
+#define GPIO1 0x4804C000
+#define GPIO_CLEARDATAOUT 0x190
+#define GPIO_SETDATAOUT 0x194
+
+#define PRU0_ARM_INTERRUPT 19
+
+#define C_ADC_DAC_MEM C24     // PRU0 mem
+#ifdef DBOX_CAPE
+#define DAC_GPIO      GPIO0
+#define DAC_CS_PIN    (1<<5) // GPIO0:5 = P9 pin 17
+#else
+#define DAC_GPIO      GPIO1
+#define DAC_CS_PIN    (1<<16) // GPIO1:16 = P9 pin 15
+#endif
+#define DAC_TRM       0       // SPI transmit and receive
+#define DAC_WL        32      // Word length
+#define DAC_CLK_MODE  1       // SPI mode
+#define DAC_CLK_DIV   1       // Clock divider (48MHz / 2^n)
+#define DAC_DPE       1       // d0 = receive, d1 = transmit
+
+#define AD5668_COMMAND_OFFSET 24
+#define AD5668_ADDRESS_OFFSET 20
+#define AD5668_DATA_OFFSET    4
+#define AD5668_REF_OFFSET     0
+
+#ifdef DBOX_CAPE
+#define ADC_GPIO      GPIO1
+#define ADC_CS_PIN    (1<<16) // GPIO1:16 = P9 pin 15
+#else
+#define ADC_GPIO      GPIO1
+#define ADC_CS_PIN    (1<<17) // GPIO1:17 = P9 pin 23
+#endif
+#define ADC_TRM       0       // SPI transmit and receive
+#define ADC_WL        16      // Word length
+#define ADC_CLK_MODE  0       // SPI mode
+#define ADC_CLK_DIV   1       // Clock divider (48MHz / 2^n)
+#define ADC_DPE       1       // d0 = receive, d1 = transmit
+
+#define AD7699_CFG_MASK       0xF120 // Mask for config update, unipolar, full BW
+#define AD7699_CHANNEL_OFFSET 9      // 7 bits offset of a 14-bit left-justified word
+#define AD7699_SEQ_OFFSET     3      // sequencer (0 = disable, 3 = scan all)
+
+#define SHARED_COMM_MEM_BASE  0x00010000  // Location where comm flags are written
+#define COMM_SHOULD_STOP      0		  // Set to be nonzero when loop should stop
+#define COMM_CURRENT_BUFFER   4           // Which buffer we are on
+#define COMM_BUFFER_FRAMES    8           // How many frames per buffer
+#define COMM_SHOULD_SYNC      12          // Whether to synchronise to an external clock
+#define COMM_SYNC_ADDRESS     16          // Which memory address to find the GPIO on
+#define COMM_SYNC_PIN_MASK    20          // Which pin to read for the sync
+#define COMM_LED_ADDRESS      24          // Which memory address to find the status LED on
+#define COMM_LED_PIN_MASK     28          // Which pin to write to change LED
+#define COMM_FRAME_COUNT      32	  // How many frames have elapse since beginning
+#define COMM_USE_SPI          36          // Whether or not to use SPI ADC and DAC
+	
+#define MCASP0_BASE 0x48038000
+#define MCASP1_BASE 0x4803C000
+
+#define MCASP_PWRIDLESYSCONFIG 		0x04
+#define MCASP_PFUNC			0x10
+#define MCASP_PDIR			0x14
+#define MCASP_PDOUT			0x18
+#define MCASP_PDSET			0x1C
+#define MCASP_PDIN			0x1C
+#define MCASP_PDCLR			0x20
+#define MCASP_GBLCTL			0x44
+#define MCASP_AMUTE			0x48
+#define MCASP_DLBCTL			0x4C
+#define MCASP_DITCTL			0x50
+#define MCASP_RGBLCTL			0x60
+#define MCASP_RMASK			0x64
+#define MCASP_RFMT			0x68
+#define MCASP_AFSRCTL			0x6C
+#define MCASP_ACLKRCTL			0x70
+#define MCASP_AHCLKRCTL			0x74
+#define MCASP_RTDM			0x78
+#define MCASP_RINTCTL			0x7C
+#define MCASP_RSTAT			0x80
+#define MCASP_RSLOT			0x84
+#define MCASP_RCLKCHK			0x88
+#define MCASP_REVTCTL			0x8C
+#define MCASP_XGBLCTL			0xA0
+#define MCASP_XMASK			0xA4
+#define MCASP_XFMT			0xA8
+#define MCASP_AFSXCTL			0xAC
+#define MCASP_ACLKXCTL			0xB0
+#define MCASP_AHCLKXCTL			0xB4
+#define MCASP_XTDM			0xB8
+#define MCASP_XINTCTL			0xBC
+#define MCASP_XSTAT			0xC0
+#define MCASP_XSLOT			0xC4
+#define MCASP_XCLKCHK			0xC8
+#define MCASP_XEVTCTL			0xCC
+#define MCASP_SRCTL0			0x180
+#define MCASP_SRCTL1			0x184
+#define MCASP_SRCTL2			0x188
+#define MCASP_SRCTL3			0x18C
+#define MCASP_SRCTL4			0x190
+#define MCASP_SRCTL5			0x194
+#define MCASP_XBUF0			0x200
+#define MCASP_XBUF1			0x204
+#define MCASP_XBUF2			0x208
+#define MCASP_XBUF3			0x20C
+#define MCASP_XBUF4			0x210
+#define MCASP_XBUF5			0x214
+#define MCASP_RBUF0			0x280
+#define MCASP_RBUF1			0x284
+#define MCASP_RBUF2			0x288
+#define MCASP_RBUF3			0x28C
+#define MCASP_RBUF4			0x290
+#define MCASP_RBUF5			0x294
+#define MCASP_WFIFOCTL			0x1000
+#define MCASP_WFIFOSTS			0x1004
+#define MCASP_RFIFOCTL			0x1008
+#define MCASP_RFIFOSTS			0x100C
+
+#define MCASP_XSTAT_XDATA_BIT           5        // Bit to test for transmit ready
+#define MCASP_RSTAT_RDATA_BIT           5        // Bit to test for receive ready 
+	
+// Constants used for this particular audio setup
+#define MCASP_BASE 	MCASP0_BASE
+#ifdef DBOX_CAPE
+#define MCASP_SRCTL_X	MCASP_SRCTL2	// Ser. 2 is transmitter
+#define MCASP_SRCTL_R	MCASP_SRCTL0	// Ser. 0 is receiver
+#define MCASP_XBUF	MCASP_XBUF2
+#define MCASP_RBUF	MCASP_RBUF0
+#else
+#define MCASP_SRCTL_X	MCASP_SRCTL3	// Ser. 3 is transmitter
+#define MCASP_SRCTL_R	MCASP_SRCTL2	// Ser. 2 is receiver
+#define MCASP_XBUF	MCASP_XBUF3
+#define MCASP_RBUF	MCASP_RBUF2
+#endif
+	
+#define MCASP_PIN_AFSX		(1 << 28)
+#define MCASP_PIN_AHCLKX	(1 << 27)
+#define MCASP_PIN_ACLKX		(1 << 26)
+#define MCASP_PIN_AMUTE		(1 << 25)	// Also, 0 to 3 are XFR0 to XFR3
+
+#ifdef DBOX_CAPE
+#define MCASP_OUTPUT_PINS   	MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs
+#else
+#define MCASP_OUTPUT_PINS   	(1 << 3)	// Which pins are outputs
+#endif
+
+#define MCASP_DATA_MASK 	0xFFFF		// 16 bit data
+#define MCASP_DATA_FORMAT	0x807C		// MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits
+
+#define C_MCASP_MEM             C28     // Shared PRU mem
+
+// Flags for the flags register
+#define FLAG_BIT_BUFFER1	0
+#define FLAG_BIT_USE_SPI	1
+	
+// Registers used throughout
+
+// r1, r2, r3 are used for temporary storage
+#define reg_frame_current	r10		// Current frame count in SPI ADC/DAC transfer
+#define reg_frame_total		r11		// Total frame count for SPI ADC/DAC
+#define reg_dac_data		r12		// Current dword for SPI DAC
+#define reg_adc_data		r13		// Current dword for SPI ADC
+#define reg_mcasp_dac_data	r14		// Current dword for McASP DAC
+#define reg_mcasp_adc_data	r15		// Current dword for McASP ADC
+#define reg_dac_buf0		r16		// Start pointer to SPI DAC buffer 0
+#define reg_dac_buf1		r17		// Start pointer to SPI DAC buffer 1
+#define reg_dac_current		r18		// Pointer to current storage location of SPI DAC
+#define reg_adc_current		r19		// Pointer to current storage location of SPI ADC
+#define reg_mcasp_buf0		r20		// Start pointer to McASP DAC buffer 0
+#define reg_mcasp_buf1		r21		// Start pointer to McASP DAC buffer 1
+#define reg_mcasp_dac_current	r22		// Pointer to current storage location of McASP DAC
+#define reg_mcasp_adc_current	r23		// Pointer to current storage location of McASP ADC
+#define reg_flags		r24		// Buffer ID (0 and 1) and other flags
+#define reg_comm_addr		r25		// Memory address for communicating with ARM
+#define reg_spi_addr		r26		// Base address for SPI
+// r27, r28 used in macros
+#define reg_mcasp_addr		r29		// Base address for McASP
+
+	
+// Bring CS line low to write to DAC
+.macro DAC_CS_ASSERT
+      MOV r27, DAC_CS_PIN
+      MOV r28, DAC_GPIO + GPIO_CLEARDATAOUT
+      SBBO r27, r28, 0, 4
+.endm
+
+// Bring CS line high at end of DAC transaction
+.macro DAC_CS_UNASSERT
+      MOV r27, DAC_CS_PIN
+      MOV r28, DAC_GPIO + GPIO_SETDATAOUT
+      SBBO r27, r28, 0, 4
+.endm
+
+// Write to DAC TX register
+.macro DAC_TX
+.mparam data
+      SBBO data, reg_spi_addr, SPI_CH0TX, 4
+.endm
+
+// Wait for SPI to finish (uses RXS indicator)
+.macro DAC_WAIT_FOR_FINISH
+ LOOP:
+      LBBO r27, reg_spi_addr, SPI_CH0STAT, 4
+      QBBC LOOP, r27, 0
+.endm
+
+// Read the RX word to clear
+.macro DAC_DISCARD_RX
+      LBBO r27, reg_spi_addr, SPI_CH0RX, 4
+.endm
+
+// Complete DAC write with chip select
+.macro DAC_WRITE
+.mparam reg
+      DAC_CS_ASSERT
+      DAC_TX reg
+      DAC_WAIT_FOR_FINISH
+      DAC_CS_UNASSERT
+      DAC_DISCARD_RX
+.endm
+
+// Bring CS line low to write to ADC
+.macro ADC_CS_ASSERT
+      MOV r27, ADC_CS_PIN
+      MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT
+      SBBO r27, r28, 0, 4
+.endm
+
+// Bring CS line high at end of ADC transaction
+.macro ADC_CS_UNASSERT
+      MOV r27, ADC_CS_PIN
+      MOV r28, ADC_GPIO + GPIO_SETDATAOUT
+      SBBO r27, r28, 0, 4
+.endm
+
+// Write to ADC TX register
+.macro ADC_TX
+.mparam data
+      SBBO data, reg_spi_addr, SPI_CH1TX, 4
+.endm
+
+// Wait for SPI to finish (uses RXS indicator)
+.macro ADC_WAIT_FOR_FINISH
+ LOOP:
+      LBBO r27, reg_spi_addr, SPI_CH1STAT, 4
+      QBBC LOOP, r27, 0
+.endm
+
+// Read the RX word to clear; store output
+.macro ADC_RX
+.mparam data
+      LBBO data, reg_spi_addr, SPI_CH1RX, 4
+.endm
+
+// Complete ADC write+read with chip select
+.macro ADC_WRITE
+.mparam in, out
+      ADC_CS_ASSERT
+      ADC_TX in
+      ADC_WAIT_FOR_FINISH
+      ADC_RX out
+      ADC_CS_UNASSERT
+.endm
+
+// Write a McASP register
+.macro MCASP_REG_WRITE
+.mparam reg, value
+      MOV r27, value
+      SBBO r27, reg_mcasp_addr, reg, 4
+.endm
+
+// Write a McASP register beyond the 0xFF boundary
+.macro MCASP_REG_WRITE_EXT
+.mparam reg, value
+      MOV r27, value
+      MOV r28, reg
+      ADD r28, reg_mcasp_addr, r28
+      SBBO r27, r28, 0, 4
+.endm
+
+// Read a McASP register
+.macro MCASP_REG_READ
+.mparam reg, value
+      LBBO value, reg_mcasp_addr, reg, 4
+.endm
+	
+// Read a McASP register beyond the 0xFF boundary
+.macro MCASP_REG_READ_EXT
+.mparam reg, value
+      MOV r28, reg
+      ADD r28, reg_mcasp_addr, r28
+      LBBO value, r28, 0, 4
+.endm
+	
+// Set a bit and wait for it to come up
+.macro MCASP_REG_SET_BIT_AND_POLL
+.mparam reg, mask
+      MOV r27, mask
+      LBBO r28, reg_mcasp_addr, reg, 4
+      OR r28, r28, r27
+      SBBO r28, reg_mcasp_addr, reg, 4
+POLL:
+      LBBO r28, reg_mcasp_addr, reg, 4
+      AND r28, r28, r27
+      QBEQ POLL, r28, 0
+.endm
+   
+START:
+      // Set up c24 and c25 offsets with CTBIR register
+      // Thus C24 points to start of PRU0 RAM
+      MOV r3, 0x22020       // CTBIR0
+      MOV r2, 0
+      SBBO r2, r3, 0, 4
+
+      // Set up c28 pointer offset for shared PRU RAM
+      MOV r3, 0x22028       // CTPPR0
+      MOV r2, 0x00000120    // To get address 0x00012000
+      SBBO r2, r3, 0, 4
+	
+      // Load useful registers for addressing SPI
+      MOV reg_comm_addr, SHARED_COMM_MEM_BASE
+      MOV reg_spi_addr, SPI_BASE
+      MOV reg_mcasp_addr, MCASP_BASE
+	
+      // Set ARM such that PRU can write to registers
+      LBCO r0, C4, 4, 4
+      CLR r0, r0, 4
+      SBCO r0, C4, 4, 4
+
+      // Clear flags
+      MOV reg_flags, 0
+
+      // Find out whether we should use SPI ADC and DAC
+      LBBO r2, reg_comm_addr, COMM_USE_SPI, 4
+      QBEQ SPI_FLAG_CHECK_DONE, r2, 0
+      SET reg_flags, reg_flags, FLAG_BIT_USE_SPI
+
+SPI_FLAG_CHECK_DONE:
+      // If we don't use SPI, then skip all this init
+      QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
+	
+      // Init SPI clock
+      MOV r2, 0x02
+      MOV r3, CLOCK_BASE + CLOCK_SPI0
+      SBBO r2, r3, 0, 4
+
+      // Reset SPI and wait for finish
+      MOV r2, 0x02
+      SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4
+
+SPI_WAIT_RESET:
+      LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4
+      QBBC SPI_WAIT_RESET, r2, 0
+	
+      // Turn off SPI channels
+      MOV r2, 0
+      SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
+      SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
+  
+      // Set to master; chip select lines enabled (CS0 used for DAC)
+      MOV r2, 0x00
+      SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4
+  
+      // Configure CH0 for DAC
+      MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6)
+      SBBO r2, reg_spi_addr, SPI_CH0CONF, 4
+
+      // Configure CH1 for ADC
+      MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE
+      SBBO r2, reg_spi_addr, SPI_CH1CONF, 4
+   
+      // Turn on SPI channels
+      MOV r2, 0x01
+      SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
+      SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4   
+
+      // DAC power-on reset sequence
+      MOV r2, (0x07 << AD5668_COMMAND_OFFSET)
+      DAC_WRITE r2
+
+      // Initialise ADC
+      MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET)
+      ADC_WRITE r2, r2
+
+      // Enable DAC internal reference
+      MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET)
+      DAC_WRITE r2
+	
+      // Read ADC ch0 and ch1: result is always 2 samples behind so start here
+      MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET)
+      ADC_WRITE r2, r2
+
+      MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET)
+      ADC_WRITE r2, r2
+SPI_INIT_DONE:	
+	
+// Prepare McASP0 for audio
+MCASP_REG_WRITE MCASP_GBLCTL, 0			// Disable McASP
+MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0		// All serialisers off
+MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0
+MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0
+MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0
+MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0
+MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0
+
+MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02	// Power on
+MCASP_REG_WRITE MCASP_PFUNC, 0x00		// All pins are McASP
+MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS	// Set pin direction
+MCASP_REG_WRITE MCASP_DLBCTL, 0x00
+MCASP_REG_WRITE MCASP_DITCTL, 0x00
+MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK	// 16 bit data receive
+MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT	// Set data format
+MCASP_REG_WRITE MCASP_AFSRCTL, 0x100		// I2S mode
+MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80		// Sample on rising edge
+MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001		// Internal clock, not inv, /2; irrelevant?
+MCASP_REG_WRITE MCASP_RTDM, 0x03		// Enable TDM slots 0 and 1
+MCASP_REG_WRITE MCASP_RINTCTL, 0x00		// No interrupts
+MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK	// 16 bit data transmit
+MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT	// Set data format
+MCASP_REG_WRITE MCASP_AFSXCTL, 0x100		// I2S mode
+MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00		// Transmit on rising edge, sync. xmit and recv
+MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001		// External clock from AHCLKX
+MCASP_REG_WRITE MCASP_XTDM, 0x03		// Enable TDM slots 0 and 1
+MCASP_REG_WRITE MCASP_XINTCTL, 0x00		// No interrupts
+	
+MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02		// Set up receive serialiser
+MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01		// Set up transmit serialiser
+MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00	// Disable FIFOs
+MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00
+
+MCASP_REG_WRITE MCASP_XSTAT, 0xFF		// Clear transmit errors
+MCASP_REG_WRITE MCASP_RSTAT, 0xFF		// Clear receive errors
+
+MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1)	// Set RHCLKRST
+MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9)	// Set XHCLKRST
+
+// The above write sequence will have temporarily changed the AHCLKX frequency
+// The PLL needs time to settle or the sample rate will be unstable and possibly
+// cause an underrun. Give it ~1ms before going on.
+// 10ns per loop iteration = 10^-8s --> 10^5 iterations needed
+
+      MOV r2, 1 << 28
+      MOV r3, GPIO1 + GPIO_SETDATAOUT
+      SBBO r2, r3, 0, 4
+
+MOV r2, 100000
+MCASP_INIT_WAIT:	
+      SUB r2, r2, 1
+      QBNE MCASP_INIT_WAIT, r2, 0
+
+      MOV r2, 1 << 28
+      MOV r3, GPIO1 + GPIO_CLEARDATAOUT
+      SBBO r2, r3, 0, 4
+	
+MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0)	// Set RCLKRST
+MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8)	// Set XCLKRST
+MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2)	// Set RSRCLR
+MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10)	// Set XSRCLR
+MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3)	// Set RSMRST
+MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11)	// Set XSMRST
+
+MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00		// Write to the transmit buffer to prevent underflow
+
+MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4)	// Set RFRST
+MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12)	// Set XFRST
+
+// Initialisation
+LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4  // Total frame count (SPI; 2x for McASP)
+MOV reg_dac_buf0, 0                      // DAC buffer 0 start pointer
+LSL reg_dac_buf1, reg_frame_total, 4     // DAC buffer 1 start pointer = 8[ch]*2[bytes]*bufsize
+MOV reg_mcasp_buf0, 0			 // McASP DAC buffer 0 start pointer
+LSL reg_mcasp_buf1, reg_frame_total, 3   // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*2[samples/spi]*bufsize
+CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1  // Bit 0 holds which buffer we are on
+MOV r2, 0
+SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4  // Start with frame count of 0
+	
+// Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied
+// the first output slot. Send one more word before jumping into the loop.
+MCASP_DAC_WAIT_BEFORE_LOOP:	
+      LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
+      QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT
+
+      MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00
+
+// Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC
+// in sync in terms of which TDM slot we are reading (empirically found that we should throw this away
+// rather than keep it and invert the phase)
+MCASP_ADC_WAIT_BEFORE_LOOP:
+      LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
+      QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT
+
+      MCASP_REG_READ_EXT MCASP_RBUF, r2
+	
+WRITE_ONE_BUFFER:
+      // Write a single buffer of DAC samples and read a buffer of ADC samples
+      // Load starting positions
+      MOV reg_dac_current, reg_dac_buf0         // DAC: reg_dac_current is current pointer
+      LSL reg_adc_current, reg_frame_total, 5   // 16 * 2 * bufsize
+      ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts 16 * 2 * bufsize beyond DAC
+      MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
+      LSL reg_mcasp_adc_current, reg_frame_total, 4 // McASP ADC: starts 4*2*2*bufsize beyond DAC
+      ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current
+      MOV reg_frame_current, 0
+	
+WRITE_LOOP:
+      // Write 8 channels to DAC from successive values in memory
+      // At the same time, read 8 channels from ADC
+      // Unrolled by a factor of 2 to get high and low words
+      MOV r1, 0
+ADC_DAC_LOOP:
+      QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI
+      // Load next 2 SPI DAC samples and store zero in their place
+      LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4
+      MOV r2, 0
+      SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4
+      ADD reg_dac_current, reg_dac_current, 4
+SPI_DAC_LOAD_DONE:
+
+      // On even iterations, load two more samples and choose the first one
+      // On odd iterations, transmit the second of the samples already loaded
+      QBBS MCASP_DAC_HIGH_WORD, r1, 1
+MCASP_DAC_LOW_WORD:	
+      // Load next 2 Audio DAC samples and store zero in their place
+      LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
+      MOV r2, 0
+      SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4
+      ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4
+
+      // Mask out the low word (first in little endian)
+      MOV r2, 0xFFFF
+      AND r7, reg_mcasp_dac_data, r2
+	
+      QBA MCASP_WAIT_XSTAT
+MCASP_DAC_HIGH_WORD:
+      // Take the high word of the previously loaded data
+      LSR r7, reg_mcasp_dac_data, 16
+	
+      // Two audio frames per SPI frame = 4 audio samples per SPI frame
+      // Therefore every 2 channels we send one audio sample; this loop already
+      // sends exactly two SPI channels.
+      // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
+MCASP_WAIT_XSTAT:
+      LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
+      QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT
+
+      MCASP_REG_WRITE_EXT MCASP_XBUF, r7
+	
+      // Same idea with ADC: even iterations, load the sample into the low word, odd
+      // iterations, load the sample into the high word and store
+      QBBS MCASP_ADC_HIGH_WORD, r1, 1
+MCASP_ADC_LOW_WORD:	
+      // Start ADC data at 0
+      LDI reg_mcasp_adc_data, 0
+	
+      // Now wait for a received word to become available from the audio ADC
+MCASP_WAIT_RSTAT_LOW:
+      LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
+      QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT
+
+      // Mask low word and store in ADC data register
+      MCASP_REG_READ_EXT MCASP_RBUF, r3
+      MOV r2, 0xFFFF
+      AND reg_mcasp_adc_data, r3, r2
+      QBA MCASP_ADC_DONE
+
+MCASP_ADC_HIGH_WORD:	
+      // Wait for a received word to become available from the audio ADC
+MCASP_WAIT_RSTAT_HIGH:
+      LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
+      QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT
+
+      // Read data and shift 16 bits to the left (into the high word)
+      MCASP_REG_READ_EXT MCASP_RBUF, r3
+      LSL r3, r3, 16
+      OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3
+
+      // Now store the result and increment the pointer
+      SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4
+      ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4
+MCASP_ADC_DONE:	
+      QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI
+	
+      // DAC: transmit low word (first in little endian)
+      MOV r2, 0xFFFF
+      AND r7, reg_dac_data, r2
+      LSL r7, r7, AD5668_DATA_OFFSET
+      MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
+      OR r7, r7, r8
+      LSL r8, r1, AD5668_ADDRESS_OFFSET
+      OR r7, r7, r8
+      DAC_WRITE r7
+
+      // Read ADC channels: result is always 2 commands behind
+      // Start by reading channel 2 (result is channel 0) and go
+      // to 10, but masking the channel number to be between 0 and 7
+      LDI reg_adc_data, 0
+      MOV r7, AD7699_CFG_MASK
+      ADD r8, r1, 2
+      AND r8, r8, 7
+      LSL r8, r8, AD7699_CHANNEL_OFFSET
+      OR r7, r7, r8
+      ADC_WRITE r7, r7
+
+      // Mask out only the relevant 16 bits and store in reg_adc_data
+      MOV r2, 0xFFFF
+      AND reg_adc_data, r7, r2
+
+      // Increment channel index
+      ADD r1, r1, 1
+
+      // DAC: transmit high word (second in little endian)
+      LSR r7, reg_dac_data, 16
+      LSL r7, r7, AD5668_DATA_OFFSET
+      MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
+      OR r7, r7, r8
+      LSL r8, r1, AD5668_ADDRESS_OFFSET
+      OR r7, r7, r8
+      DAC_WRITE r7
+
+      // Read ADC channels: result is always 2 commands behind
+      // Start by reading channel 2 (result is channel 0) and go
+      // to 10, but masking the channel number to be between 0 and 7
+      MOV r7, AD7699_CFG_MASK
+      ADD r8, r1, 2
+      AND r8, r8, 7
+      LSL r8, r8, AD7699_CHANNEL_OFFSET
+      OR r7, r7, r8
+      ADC_WRITE r7, r7
+
+      // Move this result up to the 16 high bits
+      LSL r7, r7, 16
+      OR reg_adc_data, reg_adc_data, r7
+
+      // Store 2 ADC words in memory
+      SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
+      ADD reg_adc_current, reg_adc_current, 4
+
+      // Repeat 4 times (2 samples per loop, r1 += 1 already happened)
+      ADD r1, r1, 1
+      QBNE ADC_DAC_LOOP, r1, 8
+      QBA ADC_DAC_LOOP_DONE
+	
+SPI_SKIP_WRITE:
+      // We get here only if the SPI ADC and DAC are disabled
+      // Just keep the loop going for McASP
+      ADD r1, r1, 2
+      QBNE ADC_DAC_LOOP, r1, 8
+	
+ADC_DAC_LOOP_DONE:	
+      // Increment number of frames, see if we have more to write
+      ADD reg_frame_current, reg_frame_current, 1
+      QBNE WRITE_LOOP, reg_frame_current, reg_frame_total
+
+WRITE_LOOP_DONE:
+      // Now done, swap the buffers and do the next one
+      // Use r2 as a temp register
+      MOV r2, reg_dac_buf0
+      MOV reg_dac_buf0, reg_dac_buf1
+      MOV reg_dac_buf1, r2
+      MOV r2, reg_mcasp_buf0
+      MOV reg_mcasp_buf0, reg_mcasp_buf1
+      MOV reg_mcasp_buf1, r2
+
+      // Notify ARM of buffer swap
+      XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1)
+      AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1)    // Mask out every but low bit
+      SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4
+
+      // Increment the frame count in the comm buffer (for status monitoring)
+      LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
+      ADD r2, r2, reg_frame_total
+      SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
+
+      // If LED blink enabled, toggle every 4096 frames
+      LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4
+      QBEQ LED_BLINK_DONE, r3, 0	
+      MOV r1, 0x1000
+      AND r2, r2, r1          // Test (frame count & 4096)
+      QBEQ LED_BLINK_OFF, r2, 0
+      LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4	
+      MOV r1, GPIO_SETDATAOUT
+      ADD r3, r3, r1          // Address for GPIO set register
+      SBBO r2, r3, 0, 4       // Set GPIO pin
+      QBA LED_BLINK_DONE
+LED_BLINK_OFF:
+      LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
+      MOV r1, GPIO_CLEARDATAOUT
+      ADD r3, r3, r1          // Address for GPIO clear register
+      SBBO r2, r3, 0, 4       // Clear GPIO pin	
+LED_BLINK_DONE:	
+	
+      QBBC TESTLOW, reg_flags, FLAG_BIT_BUFFER1
+      MOV r2, 1 << 28
+      MOV r3, GPIO1 + GPIO_SETDATAOUT
+      SBBO r2, r3, 0, 4
+      QBA TESTDONE
+TESTLOW:
+      MOV r2, 1 << 28
+      MOV r3, GPIO1 + GPIO_CLEARDATAOUT
+      SBBO r2, r3, 0, 4
+TESTDONE:
+	 
+      // Check if we should finish: flag is zero as long as it should run
+      LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4
+      QBEQ WRITE_ONE_BUFFER, r2, 0
+
+CLEANUP:
+      MCASP_REG_WRITE MCASP_GBLCTL, 0x00	// Turn off McASP
+
+      // Turn off SPI if enabled
+      QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI
+	
+      MOV r3, SPI_BASE + SPI_CH0CONF
+      LBBO r2, r3, 0, 4
+      CLR r2, r2, 13
+      CLR r2, r2, 27
+      SBBO r2, r3, 0, 4
+
+      MOV r3, SPI_BASE + SPI_CH0CTRL
+      LBBO r2, r3, 0, 4
+      CLR r2, r2, 1
+      SBBO r2, r3, 0, 4      
+SPI_CLEANUP_DONE:
+	
+      // Signal the ARM that we have finished 
+      MOV R31.b0, PRU0_ARM_INTERRUPT + 16
+      HALT
\ No newline at end of file
Binary file resources/BB-BONE-BAREAUDI-00A0.dtbo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/resources/BB-BONE-BAREAUDI-02-00A0.dts	Fri Oct 31 19:10:17 2014 +0100
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "ti,beaglebone", "ti,beaglebone-black";
+
+	/* identification */
+	part-number = "BB-BONE-BAREAUDI-02";
+	version = "00A0", "A0";
+
+	/* state the resources this cape uses */
+	exclusive-use =
+		/* the pin header uses */
+		"P9.31",	/* mcasp0: mcasp0_aclkx */
+		"P9.29",	/* mcasp0: mcasp0_fsx */
+		"P9.28",	/* mcasp0: mcasp0_axr2 */
+		"P9.25",	/* mcasp0: mcasp0_ahclkx */
+		/* the hardware ip uses */
+		"gpio1_18", "gpio1_19",
+		"mcasp0";
+
+	fragment@0 {
+		target = <&am33xx_pinmux>;
+		__overlay__ {
+
+			i2c2_pins: pinmux_i2c2_pins {
+				pinctrl-single,pins = <
+					0x150 0x72 	/*spi0_scl.i2c2_sda,SLEWCTRL_SLOW | INPUT_PULLUP |MODE2*/
+					0x154 0x72	/*spi0_d0.i2c2_scl,SLEWCTRL_SLOW | INPUT_PULLUP | MODE2*/
+				>;
+			};
+
+			bone_audio_cape_audio_pins: pinmux_bone_audio_cape_audio_pins {
+				pinctrl-single,pins = <
+					0x1ac 0x00      /* mcasp0_ahclkx,             MODE0 | INPUT */
+					0x19c 0x22		/* mcasp0_ahclkr, */
+					0x194 0x20      /* mcasp0_fsx,         	      MODE0 | OUTPUT  */
+					0x190 0x20      /* mcasp0_aclkr.mcasp0_aclkx, MODE0 | OUTPUT_PULLDOWN */
+					0x198 0x20
+				>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&mcasp0>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&bone_audio_cape_audio_pins>;
+
+			status = "okay";
+
+			op-mode = <0>;          /* MCASP_IIS_MODE */
+			tdm-slots = <2>;
+			num-serializer = <16>;
+			serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
+				2 0 1 0
+				0 0 0 0
+				0 0 0 0
+				0 0 0 0
+			>;
+			tx-num-evt = <1>;
+			rx-num-evt = <1>;
+		};
+	};
+
+};