diff projects/d-box/render.cpp @ 50:be427da6fb9c newapi

Removed old testing code that stopped audio after 10 seconds; command line parameter updates; D-Box updates (not fully working yet)
author andrewm
date Sat, 30 May 2015 12:34:32 -0500
parents 42a683058b6a
children 4f8db16f17b5
line wrap: on
line diff
--- a/projects/d-box/render.cpp	Thu May 28 17:48:42 2015 -0400
+++ b/projects/d-box/render.cpp	Sat May 30 12:34:32 2015 -0500
@@ -5,7 +5,7 @@
  *      Author: Victor Zappi
  */
 
-#include "../../include/RTAudio.h"
+#include "../../include/BeagleRT.h"
 #include "../../include/PRU.h"
 #include "StatusLED.h"
 #include "config.h"
@@ -39,7 +39,6 @@
 #define ADC_PIN6	6
 #define ADC_PIN7	7
 
-
 #define N_OCT		4.0	// maximum number of octaves on sensor 1
 
 extern vector<OscillatorBank*> gOscBanks;
@@ -49,7 +48,6 @@
 extern StatusLED gStatusLED;
 extern bool gIsLoading;
 extern bool gAudioIn;
-extern int gPeriodSize;
 
 float *gOscillatorBuffer1, *gOscillatorBuffer2;
 float *gOscillatorBufferRead, *gOscillatorBufferWrite;
@@ -78,7 +76,7 @@
 // sensor 0.
 extern float gSensor0LatestTouchPos;
 extern int gSensor0LatestTouchNum;
-uint16_t gPitchLatestInput = 0;
+float gPitchLatestInput = 0;
 
 extern float gSensor1LatestTouchPos[];
 //extern float gSensor1LatestTouchSizes[];
@@ -94,9 +92,9 @@
 
 // Loop points from matrix input 4
 const int gLoopPointsInputBufferSize	= 256;
-uint16_t gLoopPointsInputBuffer[gLoopPointsInputBufferSize];
+float gLoopPointsInputBuffer[gLoopPointsInputBufferSize];
 int gLoopPointsInputBufferPointer		= 0;
-int gLoopPointMin = 0, gLoopPointMax	= 0;
+float gLoopPointMin = 0, gLoopPointMax	= 0;
 
 // multiplier to activate or mute audio in
 int audioInStatus = 0;
@@ -106,7 +104,7 @@
 
 // pitch vars
 float octaveSplitter;
-u_int16_t semitones[((int)N_OCT*12)+1];
+float semitones[((int)N_OCT*12)+1];
 float deltaTouch	= 0;
 float deltaWeightP	= 0.5;
 float deltaWeightI	= 0.0005;
@@ -143,22 +141,21 @@
                               float *tableIn, float *tableOut,
                               float *sineTable, float sineMix);
 
-inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold,
-									uint16_t fallingThreshold, bool *rising);
+inline float hysteresis_oscillator(float input, float risingThreshold,
+									float fallingThreshold, bool *rising);
+
+void render_medium_prio();
+void render_low_prio();
 
 #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 numMatrixChannels, int numAudioChannels,
-					   int numMatrixFramesPerPeriod,
-					   int numAudioFramesPerPeriod,
-					   float matrixSampleRate, float audioSampleRate,
-					   void *userData) {
+bool initialise_render(BeagleRTContext *context, void *userData) {
 	int oscBankHopSize = *(int *)userData;
 
-	if(numMatrixChannels != 8) {
+	if(context->analogChannels != 8) {
 		printf("Error: D-Box needs matrix enabled with 8 channels.\n");
 		return false;
 	}
@@ -166,19 +163,19 @@
 	// 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 * gNumAudioChannels * sizeof(float))) {
+	if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * context->audioChannels * sizeof(float))) {
 		printf("Error allocating render buffers\n");
 		return false;
 	}
-	if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * gNumAudioChannels * sizeof(float))) {
+	if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * context->audioChannels * sizeof(float))) {
 		printf("Error allocating render buffers\n");
 		return false;
 	}
 	gOscillatorBufferWrite	= gOscillatorBuffer1;
 	gOscillatorBufferRead	= gOscillatorBuffer2;
 
-	memset(gOscillatorBuffer1, 0, oscBankHopSize * gNumAudioChannels * sizeof(float));
-	memset(gOscillatorBuffer2, 0, oscBankHopSize * gNumAudioChannels * sizeof(float));
+	memset(gOscillatorBuffer1, 0, oscBankHopSize * context->audioChannels * sizeof(float));
+	memset(gOscillatorBuffer2, 0, oscBankHopSize * context->audioChannels * 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
@@ -189,18 +186,18 @@
 		return false;
 	}
 
-	gFeedbackOscillator.initialise(8192, 10.0, matrixSampleRate);
+	gFeedbackOscillator.initialise(8192, 10.0, context->analogSampleRate);
 
 	for(int n = 0; n < gDynamicWavetableLength + 1; n++)
 		gDynamicWavetable[n] = 0;
 
 	// pitch
-	float midPos		= (float)65535/2.0;
-	octaveSplitter		= round((float)65535/(N_OCT));
+	float midPos		= 0.5;
+	octaveSplitter		= 1.0 / 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);
+	float inc 			= 1.0 / (N_OCT*12.0);
 	int i 				= -1;
 	for(int semi=middleSemitone; semi<=lastSemitone; semi++)
 		semitones[semi] = ( midPos + (++i)*inc) + 0.5;
@@ -212,7 +209,7 @@
 		audioInStatus = 1;
 
 	// filter
-	blockSize		= 2*gPeriodSize;
+	blockSize		= context->audioFrames;
 	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));
@@ -223,24 +220,23 @@
 	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].setAttackRate(.00001 * context->analogSampleRate);
+	PeakBurst[1].setAttackRate(.00001 * context->analogSampleRate);
+	PeakBurst[0].setDecayRate(.5 * context->analogSampleRate);
+	PeakBurst[1].setDecayRate(.5 * context->analogSampleRate);
 	PeakBurst[0].setSustainLevel(0.0);
 	PeakBurst[1].setSustainLevel(0.0);
 
 	// Initialise auxiliary tasks
-	if((gMediumPriorityRender = createAuxiliaryTaskLoop(&render_medium_prio, 90, "dbox-calculation-medium")) == 0)
+	if((gMediumPriorityRender = BeagleRT_createAuxiliaryTask(&render_medium_prio, BEAGLERT_AUDIO_PRIORITY - 10, "dbox-calculation-medium")) == 0)
 		return false;
-	if((gLowPriorityRender = createAuxiliaryTaskLoop(&render_low_prio, 85, "dbox-calculation-low")) == 0)
+	if((gLowPriorityRender = BeagleRT_createAuxiliaryTask(&render_low_prio, BEAGLERT_AUDIO_PRIORITY - 15, "dbox-calculation-low")) == 0)
 		return false;
 
 	return true;
 }
 
-void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
-			uint16_t *matrixIn, uint16_t *matrixOut)
+void render(BeagleRTContext *context, void *userData)
 {
 #ifdef DBOX_CAPE_TEST
 	render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut);
@@ -250,10 +246,10 @@
 
 	if(gOscBanks[gCurrentOscBank]->state==bank_playing)
 	{
-		assert(gNumAudioChannels == 2);
+		assert(context->audioChannels == 2);
 
 #ifdef OLD_OSCBANK
-		memset(audioOut, 0, numAudioFrames * gNumAudioChannels * sizeof(float));
+		memset(audioOut, 0, numAudioFrames *  * 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
@@ -290,18 +286,18 @@
 									 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives,
 									 gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/);
 				framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter;
-				audioOutWithOffset += gNumAudioChannels * gOscBanks[gCurrentOscBank]->hopCounter;
+				audioOutWithOffset +=  * 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;
+		for(unsigned int n = 0; n < context->audioFrames; n++) {
+			context->audioOut[2*n] 	  = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n]*audioInStatus;
+			context->audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->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
+			filterIn[0][n] = fabs(context->audioIn[2*n]);	// rectify for peak detection in 1
+			filterIn[1][n] = fabs(context->audioIn[2*n+1]);	// rectify for peak detection in 2
 
 			/* FIXME why doesn't this work? */
 			/*
@@ -326,19 +322,19 @@
 				gOscillatorBufferReadPointer = 0;
 
 				gOscillatorNeedsRender = true;
-				scheduleAuxiliaryTask(gMediumPriorityRender);
+				BeagleRT_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;
+		for(unsigned int n = 0; n < context->audioFrames; n++) {
+			context->audioOut[2*n] 	  = context->audioIn[2*n]*audioInStatus;
+			context->audioOut[2*n + 1] = context->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
+			filterIn[0][n] = fabs(context->audioIn[2*n]);	// rectify for peak detection in 1
+			filterIn[1][n] = fabs(context->audioIn[2*n+1]);	// rectify for peak detection in 2
 		}
 	}
 
@@ -346,7 +342,7 @@
 	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++) {
+	for(unsigned int n = 0; n < context->analogFrames; n++) {
 
 
 		/* Matrix Out 0, In 0
@@ -354,12 +350,12 @@
 		 * CV loop
 		 * Controls pitch of sound
 		 */
-		int touchPosInt = gSensor0LatestTouchPos * 65536.0;
+		float touchPosInt = gSensor0LatestTouchPos;
 		if(touchPosInt < 0) touchPosInt = 0;
-		if(touchPosInt > 65535) touchPosInt = 65535;
-		matrixOut[n*8 + DAC_PIN0] = touchPosInt;
+		if(touchPosInt > 1.0) touchPosInt = 1.0;
+		context->analogOut[n*8 + DAC_PIN0] = touchPosInt;
 
-		gPitchLatestInput = matrixIn[n*8 + ADC_PIN0];
+		gPitchLatestInput = context->analogIn[n*8 + ADC_PIN0];
 
 
 		/* Matrix Out 7
@@ -372,17 +368,17 @@
 		if(gSensor0LatestTouchNum>0)
 		{
 			// current pitch is gPitchLatestInput, already retrieved
-			semitoneIndex	= (  ( (float)gPitchLatestInput / 65535)*12*N_OCT  )+0.5;	// closest semitone
+			semitoneIndex	= ( gPitchLatestInput * 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
+		float 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
+		if(nextOut > 1.0) nextOut = 1.0;										// clamp
+		context->analogOut[n*8 + DAC_PIN7] = nextOut;										// send next nextOut
 
 
 		/*
@@ -392,7 +388,8 @@
 		 * Controls speed of playback
 		 */
 		bool wasRising = gSpeedHysteresisOscillatorRising;
-		matrixOut[n*8 + DAC_PIN1] = hysteresis_oscillator(matrixIn[n*8 + ADC_PIN1], 48000, 16000, &gSpeedHysteresisOscillatorRising);
+		context->analogOut[n*8 + DAC_PIN1] = hysteresis_oscillator(context->analogIn[n*8 + ADC_PIN1], 48000.0/65536.0,
+																	16000.0/65536.0, &gSpeedHysteresisOscillatorRising);
 
 		// Find interval of zero crossing
 		if(wasRising && !gSpeedHysteresisOscillatorRising) {
@@ -415,12 +412,12 @@
 		 * Controls wavetable used for oscillator bank
 		 */
 
-		int tableLength = gFeedbackOscillator.process(matrixIn[n*8 + ADC_PIN2], &matrixOut[n*8 + DAC_PIN2]);
+		int tableLength = gFeedbackOscillator.process(context->analogIn[n*8 + ADC_PIN2], &context->analogOut[n*8 + DAC_PIN2]);
 		if(tableLength != 0) {
 			gFeedbackOscillatorTableLength = tableLength;
 			gFeedbackOscillatorTable = gFeedbackOscillator.wavetable();
 			gDynamicWavetableNeedsRender = true;
-			scheduleAuxiliaryTask(gLowPriorityRender);
+			BeagleRT_scheduleAuxiliaryTask(gLowPriorityRender);
 		}
 
 		/*
@@ -432,10 +429,10 @@
 		 */
 		volatile int touchCount = gSensor1LatestTouchCount;
 		if(touchCount == 0)
-			matrixOut[n*8 + DAC_PIN3] = 0;
+			context->analogOut[n*8 + DAC_PIN3] = 0;
 		else {
 			int touchIndex = (gMatrixSampleCount >> 5) % touchCount;
-			matrixOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f;
+			context->analogOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f / 65536.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
@@ -443,33 +440,33 @@
 				// let's say 24 samples into it.
 
 				// FIXME this won't work for p > 2
-				gSensor1InputDelayCounter = 24 + 2*numMatrixFrames;
+				gSensor1InputDelayCounter = 24 + 2*context->analogFrames;
 				gSensor1InputIndex = touchIndex;
 			}
 			gSensor1LastTouchIndex = touchIndex;
 		}
 
 		if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) {
-			gSensor1MatrixTouchPos[gSensor1InputIndex] = (float)matrixIn[n*8 + ADC_PIN3] / 65536.0f;
+			gSensor1MatrixTouchPos[gSensor1InputIndex] = context->analogIn[n*8 + ADC_PIN3];
 		}
 
 		/* Matrix Out 4
 		 *
 		 * Sensor 1 last pos
 		 */
-		touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex] * 65536.0;
+		touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex];
 		if(touchPosInt < 0) touchPosInt = 0;
-		if(touchPosInt > 65535) touchPosInt = 65535;
-		matrixOut[n*8 + DAC_PIN4] = touchPosInt;
+		if(touchPosInt > 1.0) touchPosInt = 1.0;
+		context->analogOut[n*8 + DAC_PIN4] = touchPosInt;
 
 		/* Matrix In 4
 		 *
 		 * Loop points selector
 		 */
-		gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = matrixIn[n*8 + ADC_PIN4];
+		gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = context->analogIn[n*8 + ADC_PIN4];
 		if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) {
 			// Find min and max values
-			uint16_t loopMax = 0, loopMin = 65535;
+			float loopMax = 0, loopMin = 1.0;
 			for(int i = 0; i < gLoopPointsInputBufferSize; i++) {
 				if(gLoopPointsInputBuffer[i] < loopMin)
 					loopMin = gLoopPointsInputBuffer[i];
@@ -503,8 +500,8 @@
 
 		PeakBurst[0].process(1);
 
-		int convAudio = burstOut*peak[0]*65535;
-		matrixOut[n*8 + DAC_PIN5] = convAudio;
+		float convAudio = burstOut*peak[0];
+		context->analogOut[n*8 + DAC_PIN5] = convAudio;
 		prevFiltered[0] = filterOut[0][n*2+1];
 		if(prevFiltered[0]>1)
 			prevFiltered[0] = 1;
@@ -513,8 +510,8 @@
 		 *
 		 * Dissonance, via changing frequency motion of partials
 		 */
-		float amount = (float)matrixIn[n*8 + ADC_PIN5] / 65536.0f;
-		gOscBanks[gCurrentOscBank]->freqMovement = 1-amount;
+		float amount = (float)context->analogIn[n*8 + ADC_PIN5];
+		gOscBanks[gCurrentOscBank]->freqMovement = 1.0 - amount;
 
 
 
@@ -537,8 +534,8 @@
 
 		PeakBurst[1].process(1);
 
-		convAudio = burstOut*peak[1]*65535;
-		matrixOut[n*8 + DAC_PIN6] = convAudio;
+		convAudio = burstOut*peak[1];
+		context->analogOut[n*8 + DAC_PIN6] = convAudio;
 		prevFiltered[1] = filterOut[1][n*2+1];
 		if(prevFiltered[1]>1)
 			prevFiltered[1] = 1;
@@ -550,14 +547,14 @@
 		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;
+				float input = context->analogIn[n*8 + ADC_PIN6];
+				const float hystValue = 16000.0 / 65536.0;
 
-				int upHysteresisValue = ((gCurrentOscBank + 1) * 65536 + hystValue) / gOscBanks.size();
-				int downHysteresisValue = (gCurrentOscBank * 65536 - hystValue) / gOscBanks.size();
+				float upHysteresisValue = ((gCurrentOscBank + 1) + hystValue) / gOscBanks.size();
+				float downHysteresisValue = (gCurrentOscBank - hystValue) / gOscBanks.size();
 
 				if(input > upHysteresisValue || input < downHysteresisValue) {
-					gNextOscBank = input * gOscBanks.size() / 65536;
+					gNextOscBank = input * gOscBanks.size();
 					if(gNextOscBank < 0)
 						gNextOscBank = 0;
 					if((unsigned)gNextOscBank >= gOscBanks.size())
@@ -572,8 +569,8 @@
 		 * 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);
+		gLastFSRValue = context->analogIn[n*8 + ADC_PIN7] * 1799.0;
+		//gLastFSRValue = 1799 - context->analogIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0);
 		//dbox_printf("%i\n",gLastFSRValue);
 
 		gMatrixSampleCount++;
@@ -590,7 +587,7 @@
 		gOscillatorNeedsRender = false;
 
 		/* Render one frame into the write buffer */
-		memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * gNumAudioChannels * sizeof(float));
+		memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * 2 * sizeof(float)); /* assumes 2 audio channels */
 
 		oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite,
 							 gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize,
@@ -600,7 +597,7 @@
 							 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives,
 							 /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable);
 
-		gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * gNumAudioChannels;
+		gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * 2;
 
 		/* Update the pitch right before the hop
 		 * Total CV range +/- N_OCT octaves
@@ -681,7 +678,7 @@
 				gOscBanks[gCurrentOscBank]->lookupTable, sineMix);
 	}
 
-	if(gLoopPointMin >= 60000 && gLoopPointMax >= 60000) {
+	if(gLoopPointMin >= 60000.0/65536.0 && gLoopPointMax >= 60000.0/65536.0) {
 		// KLUDGE!
 		if(gCurrentOscBank == 0)
 			gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1);
@@ -689,8 +686,8 @@
 			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;
+		float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop();
+		float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop();
 
 		int intLoopPointMin = normLoopPointMin;
 		if(intLoopPointMin < 1)
@@ -733,7 +730,7 @@
 }
 
 // Clean up at the end of render
-void cleanup_render()
+void cleanup_render(BeagleRTContext *context, void *userData)
 {
 	free(gOscillatorBuffer1);
 	free(gOscillatorBuffer2);
@@ -765,9 +762,9 @@
 }
 
 // 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)
+inline float hysteresis_oscillator(float input, float risingThreshold, float fallingThreshold, bool *rising)
 {
-	uint16_t value;
+	float value;
 
 	if(*rising) {
 		if(input > risingThreshold) {
@@ -775,12 +772,12 @@
 			value = 0;
 		}
 		else
-			value = 65535;
+			value = 1.0;
 	}
 	else {
 		if(input < fallingThreshold) {
 			*rising = true;
-			value = 65535;
+			value = 1.0;
 		}
 		else
 			value = 0;