changeset 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 def3b8cf9749
children dbc76783db2a
files examples/08-PureData/digital/_main.pd scripts/hvresources/heavy_render.cpp
diffstat 2 files changed, 120 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/examples/08-PureData/digital/_main.pd	Tue Jun 21 14:26:33 2016 +0100
+++ b/examples/08-PureData/digital/_main.pd	Tue Jun 21 14:27:26 2016 +0100
@@ -1,4 +1,4 @@
-#N canvas 279 78 857 690 10;
+#N canvas 272 16 857 690 10;
 #X obj 18 477 osc~ 200;
 #X obj 57 522 *~;
 #X obj 112 405 line~ 1;
@@ -7,8 +7,8 @@
 #X msg 209 439 1 \, 0 200;
 #X obj 210 405 select 1;
 #X obj 140 531 *~;
-#X obj 484 552 s bela_setDigital;
-#X obj 484 483 loadbang;
+#X obj 534 622 s bela_setDigital;
+#X obj 534 553 loadbang;
 #X msg 65 445 0;
 #X obj 116 332 r bela_digitalIn12;
 #X obj 422 217 r bela_digitalIn14;
@@ -33,7 +33,7 @@
 #X msg 584 281 0;
 #X obj 637 221 select 1 0;
 #X obj 80 663 dac~ 3 4;
-#X msg 388 503 disable 12;
+#X msg 458 576 disable 12;
 #X obj 158 595 *~ 0.5;
 #X obj 157 622 +~ 0.5;
 #X obj 53 584 *~ 0.5;
@@ -41,7 +41,7 @@
 #X text 183 37 This is just a stub ...;
 #X obj 308 643 dac~ 1 2;
 #X obj 311 606 *~ 0.1;
-#X obj 303 576 osc~ 120;
+#X obj 337 550 osc~ 120;
 #X msg 585 438 0;
 #X obj 649 185 print digitalIn16;
 #X obj 672 373 print digitalIn14;
@@ -49,12 +49,20 @@
 15 and 14 \, 13 and 12 Have fun figuring out the pins on P8 (or P9
 ???) If you do it properly \, you can measure roundtrip latency with
 multiple digital/analog feed-forward networs;
-#X msg 484 514 out 11 \, in 12 \, out 13 \, in 14 \, out 15 \, in 16
-\, in 17 ~;
 #X obj 552 112 loadbang;
 #X obj 206 291 print digitalIn12;
 #X text 548 130 connect a switch to digitalIn16 or turn on the metro
 here;
+#X obj 287 449 adc~ 17;
+#X obj 299 506 phasor~ 300;
+#X obj 293 539 *~;
+#X obj 409 622 dac~ 26;
+#X msg 534 584 out 11 \, in 12 \, out 13 \, in 14 \, out 15 \, in 16
+\, in 17 ~ \, out 26 ~;
+#X obj 378 427 phasor~ 0.2;
+#X obj 373 455 *~ 1000;
+#X obj 620 524 dac~ 27 28 29 30;
+#X obj 621 466 osc~ 30;
 #X connect 0 0 1 0;
 #X connect 0 0 7 0;
 #X connect 1 0 37 0;
@@ -65,7 +73,7 @@
 #X connect 6 0 5 0;
 #X connect 6 0 10 0;
 #X connect 7 0 35 0;
-#X connect 9 0 47 0;
+#X connect 9 0 54 0;
 #X connect 10 0 0 1;
 #X connect 11 0 3 0;
 #X connect 12 0 13 0;
@@ -73,7 +81,7 @@
 #X connect 12 0 45 0;
 #X connect 14 0 15 0;
 #X connect 14 0 30 0;
-#X connect 14 0 49 0;
+#X connect 14 0 48 0;
 #X connect 16 0 21 0;
 #X connect 17 0 16 1;
 #X connect 18 0 16 0;
@@ -101,5 +109,13 @@
 #X connect 38 0 33 0;
 #X connect 41 0 40 0;
 #X connect 42 0 41 0;
+#X connect 42 0 53 0;
+#X connect 42 0 57 3;
 #X connect 43 0 42 1;
-#X connect 47 0 8 0;
+#X connect 50 0 52 0;
+#X connect 51 0 52 1;
+#X connect 52 0 40 1;
+#X connect 54 0 8 0;
+#X connect 55 0 56 0;
+#X connect 56 0 42 0;
+#X connect 58 0 57 0;
--- 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;
 }