diff scripts/hvresources/heavy_render.cpp @ 482:4d5edf7ee953 prerelease

heavy: support for signal-rate digitals and Scope.
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 21 Jun 2016 14:27:26 +0100
parents 4ff80956c27a
children 7f8d1a3e4cef
line wrap: on
line diff
--- a/scripts/hvresources/heavy_render.cpp	Tue Jun 21 14:26:33 2016 +0100
+++ b/scripts/hvresources/heavy_render.cpp	Tue Jun 21 14:27:26 2016 +0100
@@ -13,8 +13,9 @@
 
 #include <Bela.h>
 #include <Midi.h>
+#include <Scope.h>
 #include <cmath>
-#include "Heavy_bbb.h"
+#include <Heavy_bbb.h>
 #include <string.h>
 #include <stdlib.h>
 #include <string.h>
@@ -133,16 +134,27 @@
  * SETUP, RENDER LOOP & CLEANUP
  */
 
+// 2 audio + (up to)8 analog + (up to) 16 digital + 4 scope outputs
+static const unsigned int gChannelsInUse = 30;
+static unsigned int gAnalogChannelsInUse = 8; // hard-coded for the moment, TODO: get it at run-time from hv_context
+//static const unsigned int gFirstAudioChannel = 0;
+static const unsigned int gFirstAnalogChannel = 2;
+static const unsigned int gFirstDigitalChannel = 10;
+static const unsigned int gFirstScopeChannel = 26;
+static unsigned int gDigitalSigInChannelsInUse;
+static unsigned int gDigitalSigOutChannelsInUse;
 
-
-// Midi
+// Bela Midi
 Midi midi;
 unsigned int hvMidiHashes[7];
+// Bela Scope
+Scope scope;
+const unsigned int gMaxScopeChannels = 4;
+unsigned int gScopeChannelsInUse;
+float* gScopeOut;
 
 
 bool setup(BelaContext *context, void *userData)	{
-
-	printf("top o setup\n");
 	/* HEAVY */
 	hvMidiHashes[kmmNoteOn] = hv_stringToHash("__hv_notein");
 	hvMidiHashes[kmmNoteOff] = hv_stringToHash("noteoff"); // this is handled differently, see the render function
@@ -152,15 +164,23 @@
 	hvMidiHashes[kmmChannelPressure] = hv_stringToHash("touchin");
 	hvMidiHashes[kmmPitchBend] = hv_stringToHash("bendin");
 
-	printf("after midi o setup\n");
 	gHeavyContext = hv_bbb_new(context->audioSampleRate);
 
-	printf("aftet new  o setup\n");
 	gHvInputChannels = hv_getNumInputChannels(gHeavyContext);
 	gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext);
 
-	rt_printf("Starting Heavy context with %d input channels and %d output channels\n",
+	gScopeChannelsInUse = gHvOutputChannels > gFirstScopeChannel ?
+			gHvOutputChannels - gFirstScopeChannel : 0;
+	gDigitalSigInChannelsInUse = gHvInputChannels > gFirstDigitalChannel ?
+			gHvInputChannels - gFirstDigitalChannel : 0;
+	gDigitalSigOutChannelsInUse = gHvOutputChannels > gFirstDigitalChannel ?
+			gHvOutputChannels - gFirstDigitalChannel - gScopeChannelsInUse: 0;
+
+	printf("Starting Heavy context with %d input channels and %d output channels\n",
 			  gHvInputChannels, gHvOutputChannels);
+	printf("Channels in use:\n");
+	printf("Digital in : %u, Digital out: %u\n", gDigitalSigInChannelsInUse, gDigitalSigOutChannelsInUse);
+	printf("Scope out: %u\n", gScopeChannelsInUse);
 
 	if(gHvInputChannels != 0) {
 		gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float));
@@ -168,7 +188,6 @@
 	if(gHvOutputChannels != 0) {
 		gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float));
 	}
-	printf("mid o setup\n");
 
 	gInverseSampleRate = 1.0 / context->audioSampleRate;
 
@@ -182,6 +201,11 @@
 	midi.writeTo(0);
 	midi.enableParser(true);
 
+	if(gScopeChannelsInUse > 0){
+		// block below copy/pasted from libpd, except
+		scope.setup(gScopeChannelsInUse, context->audioSampleRate);
+		gScopeOut = new float[gScopeChannelsInUse];
+	}
 	// Bela digital
 	dcm.setCallback(sendDigitalMessage);
 	if(context->digitalChannels > 0){
@@ -191,7 +215,6 @@
 	}
 	// unlike libpd, no need here to bind the bela_digitalOut.. receivers
 
-	printf("end o setup\n");
 	return true;
 }
 
@@ -303,13 +326,30 @@
 
 	// Bela digital in
 	// note: in multiple places below we assume that the number of digital frames is same as number of audio
-	// digital in at message-rate
+	// Bela digital in at message-rate
 	dcm.processInput(context->digital, context->digitalFrames);
 
 	// Bela digital in at signal-rate
-	// TODO: not really straightforward to implement as Heavy determines the number of channels in use at compile time
-	// on the basis of the number of adc~ / dac~ of the patch ... Maybe we should always include
-	// a dummy [adc~ 27] [dac~ 27] to make sure all channels are always allocated and then leave them all unprocessed ?
+	if(gDigitalSigInChannelsInUse > 0)
+	{
+		unsigned int j, k;
+		float *p0, *p1;
+		const unsigned int gLibpdBlockSize = context->audioFrames;
+		const unsigned int  audioFrameBase = 0;
+		float* gInBuf = gHvInputBuffers;
+		// block below copy/pasted from libpd, except
+		// 16 has been replaced with gDigitalSigInChannelsInUse
+		for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
+			unsigned int digitalFrame = audioFrameBase + j;
+			for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstDigitalChannel;
+					k < gDigitalSigInChannelsInUse; ++k, p1 += gLibpdBlockSize) {
+				if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate
+					*p1 = digitalRead(context, digitalFrame, k);
+				}
+			}
+		}
+	}
+
 
 	// replacement for bang~ object
 	//hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b");
@@ -317,11 +357,46 @@
 	hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames);
 
 	// Bela digital out
-	// digital out at signal-rate
-	// TODO: see note above.
+	// Bela digital out at signal-rate
+	if(gDigitalSigOutChannelsInUse > 0)
+	{
+			unsigned int j, k;
+			float *p0, *p1;
+			const unsigned int gLibpdBlockSize = context->audioFrames;
+			const unsigned int  audioFrameBase = 0;
+			float* gOutBuf = gHvOutputBuffers;
+			// block below copy/pasted from libpd, except
+			// context->digitalChannels has been replaced with gDigitalSigOutChannelsInUse
+			for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
+				unsigned int digitalFrame = (audioFrameBase + j);
+				for (k = 0, p1 = p0  + gLibpdBlockSize * gFirstDigitalChannel;
+						k < gDigitalSigOutChannelsInUse; k++, p1 += gLibpdBlockSize) {
+					if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate
+						digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5);
+					}
+				}
+			}
+	}
+	// Bela digital out at message-rate
+	dcm.processOutput(context->digital, context->digitalFrames);
 
-	// digital out at message-rate
-	dcm.processOutput(context->digital, context->digitalFrames);
+	// Bela scope
+	if(gScopeChannelsInUse > 0)
+	{
+		unsigned int j, k;
+		float *p0, *p1;
+		const unsigned int gLibpdBlockSize = context->audioFrames;
+		const unsigned int  audioFrameBase = 0;
+		float* gOutBuf = gHvOutputBuffers;
+
+		// block below copy/pasted from libpd
+		for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
+			for (k = 0, p1 = p0  + gLibpdBlockSize * gFirstScopeChannel; k < gScopeChannelsInUse; k++, p1 += gLibpdBlockSize) {
+				gScopeOut[k] = *p1;
+			}
+			scope.log(gScopeOut[0], gScopeOut[1], gScopeOut[2], gScopeOut[3]);
+		}
+	}
 
 	// Interleave the output data
 	if(gHvOutputBuffers != NULL) {
@@ -354,5 +429,5 @@
 		free(gHvInputBuffers);
 	if(gHvOutputBuffers != NULL)
 		free(gHvOutputBuffers);
-
+	delete[] gScopeOut;
 }