comparison 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
comparison
equal deleted inserted replaced
481:def3b8cf9749 482:4d5edf7ee953
11 * 11 *
12 */ 12 */
13 13
14 #include <Bela.h> 14 #include <Bela.h>
15 #include <Midi.h> 15 #include <Midi.h>
16 #include <Scope.h>
16 #include <cmath> 17 #include <cmath>
17 #include "Heavy_bbb.h" 18 #include <Heavy_bbb.h>
18 #include <string.h> 19 #include <string.h>
19 #include <stdlib.h> 20 #include <stdlib.h>
20 #include <string.h> 21 #include <string.h>
21 #include <DigitalChannelManager.h> 22 #include <DigitalChannelManager.h>
22 23
131 132
132 /* 133 /*
133 * SETUP, RENDER LOOP & CLEANUP 134 * SETUP, RENDER LOOP & CLEANUP
134 */ 135 */
135 136
136 137 // 2 audio + (up to)8 analog + (up to) 16 digital + 4 scope outputs
137 138 static const unsigned int gChannelsInUse = 30;
138 // Midi 139 static unsigned int gAnalogChannelsInUse = 8; // hard-coded for the moment, TODO: get it at run-time from hv_context
140 //static const unsigned int gFirstAudioChannel = 0;
141 static const unsigned int gFirstAnalogChannel = 2;
142 static const unsigned int gFirstDigitalChannel = 10;
143 static const unsigned int gFirstScopeChannel = 26;
144 static unsigned int gDigitalSigInChannelsInUse;
145 static unsigned int gDigitalSigOutChannelsInUse;
146
147 // Bela Midi
139 Midi midi; 148 Midi midi;
140 unsigned int hvMidiHashes[7]; 149 unsigned int hvMidiHashes[7];
150 // Bela Scope
151 Scope scope;
152 const unsigned int gMaxScopeChannels = 4;
153 unsigned int gScopeChannelsInUse;
154 float* gScopeOut;
141 155
142 156
143 bool setup(BelaContext *context, void *userData) { 157 bool setup(BelaContext *context, void *userData) {
144
145 printf("top o setup\n");
146 /* HEAVY */ 158 /* HEAVY */
147 hvMidiHashes[kmmNoteOn] = hv_stringToHash("__hv_notein"); 159 hvMidiHashes[kmmNoteOn] = hv_stringToHash("__hv_notein");
148 hvMidiHashes[kmmNoteOff] = hv_stringToHash("noteoff"); // this is handled differently, see the render function 160 hvMidiHashes[kmmNoteOff] = hv_stringToHash("noteoff"); // this is handled differently, see the render function
149 hvMidiHashes[kmmControlChange] = hv_stringToHash("__hv_ctlin"); 161 hvMidiHashes[kmmControlChange] = hv_stringToHash("__hv_ctlin");
150 hvMidiHashes[kmmProgramChange] = hv_stringToHash("pgmin"); 162 hvMidiHashes[kmmProgramChange] = hv_stringToHash("pgmin");
151 hvMidiHashes[kmmPolyphonicKeyPressure] = hv_stringToHash("polytouchin"); 163 hvMidiHashes[kmmPolyphonicKeyPressure] = hv_stringToHash("polytouchin");
152 hvMidiHashes[kmmChannelPressure] = hv_stringToHash("touchin"); 164 hvMidiHashes[kmmChannelPressure] = hv_stringToHash("touchin");
153 hvMidiHashes[kmmPitchBend] = hv_stringToHash("bendin"); 165 hvMidiHashes[kmmPitchBend] = hv_stringToHash("bendin");
154 166
155 printf("after midi o setup\n");
156 gHeavyContext = hv_bbb_new(context->audioSampleRate); 167 gHeavyContext = hv_bbb_new(context->audioSampleRate);
157 168
158 printf("aftet new o setup\n");
159 gHvInputChannels = hv_getNumInputChannels(gHeavyContext); 169 gHvInputChannels = hv_getNumInputChannels(gHeavyContext);
160 gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext); 170 gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext);
161 171
162 rt_printf("Starting Heavy context with %d input channels and %d output channels\n", 172 gScopeChannelsInUse = gHvOutputChannels > gFirstScopeChannel ?
173 gHvOutputChannels - gFirstScopeChannel : 0;
174 gDigitalSigInChannelsInUse = gHvInputChannels > gFirstDigitalChannel ?
175 gHvInputChannels - gFirstDigitalChannel : 0;
176 gDigitalSigOutChannelsInUse = gHvOutputChannels > gFirstDigitalChannel ?
177 gHvOutputChannels - gFirstDigitalChannel - gScopeChannelsInUse: 0;
178
179 printf("Starting Heavy context with %d input channels and %d output channels\n",
163 gHvInputChannels, gHvOutputChannels); 180 gHvInputChannels, gHvOutputChannels);
181 printf("Channels in use:\n");
182 printf("Digital in : %u, Digital out: %u\n", gDigitalSigInChannelsInUse, gDigitalSigOutChannelsInUse);
183 printf("Scope out: %u\n", gScopeChannelsInUse);
164 184
165 if(gHvInputChannels != 0) { 185 if(gHvInputChannels != 0) {
166 gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float)); 186 gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float));
167 } 187 }
168 if(gHvOutputChannels != 0) { 188 if(gHvOutputChannels != 0) {
169 gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float)); 189 gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float));
170 } 190 }
171 printf("mid o setup\n");
172 191
173 gInverseSampleRate = 1.0 / context->audioSampleRate; 192 gInverseSampleRate = 1.0 / context->audioSampleRate;
174 193
175 // Set heavy print hook 194 // Set heavy print hook
176 hv_setPrintHook(gHeavyContext, printHook); 195 hv_setPrintHook(gHeavyContext, printHook);
180 // TODO: change these hardcoded port values and actually change them in the Midi class 199 // TODO: change these hardcoded port values and actually change them in the Midi class
181 midi.readFrom(0); 200 midi.readFrom(0);
182 midi.writeTo(0); 201 midi.writeTo(0);
183 midi.enableParser(true); 202 midi.enableParser(true);
184 203
204 if(gScopeChannelsInUse > 0){
205 // block below copy/pasted from libpd, except
206 scope.setup(gScopeChannelsInUse, context->audioSampleRate);
207 gScopeOut = new float[gScopeChannelsInUse];
208 }
185 // Bela digital 209 // Bela digital
186 dcm.setCallback(sendDigitalMessage); 210 dcm.setCallback(sendDigitalMessage);
187 if(context->digitalChannels > 0){ 211 if(context->digitalChannels > 0){
188 for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){ 212 for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){
189 dcm.setCallbackArgument(ch, hvDigitalInHashes[ch]); 213 dcm.setCallbackArgument(ch, hvDigitalInHashes[ch]);
190 } 214 }
191 } 215 }
192 // unlike libpd, no need here to bind the bela_digitalOut.. receivers 216 // unlike libpd, no need here to bind the bela_digitalOut.. receivers
193 217
194 printf("end o setup\n");
195 return true; 218 return true;
196 } 219 }
197 220
198 221
199 void render(BelaContext *context, void *userData) 222 void render(BelaContext *context, void *userData)
301 } 324 }
302 } 325 }
303 326
304 // Bela digital in 327 // Bela digital in
305 // note: in multiple places below we assume that the number of digital frames is same as number of audio 328 // note: in multiple places below we assume that the number of digital frames is same as number of audio
306 // digital in at message-rate 329 // Bela digital in at message-rate
307 dcm.processInput(context->digital, context->digitalFrames); 330 dcm.processInput(context->digital, context->digitalFrames);
308 331
309 // Bela digital in at signal-rate 332 // Bela digital in at signal-rate
310 // TODO: not really straightforward to implement as Heavy determines the number of channels in use at compile time 333 if(gDigitalSigInChannelsInUse > 0)
311 // on the basis of the number of adc~ / dac~ of the patch ... Maybe we should always include 334 {
312 // a dummy [adc~ 27] [dac~ 27] to make sure all channels are always allocated and then leave them all unprocessed ? 335 unsigned int j, k;
336 float *p0, *p1;
337 const unsigned int gLibpdBlockSize = context->audioFrames;
338 const unsigned int audioFrameBase = 0;
339 float* gInBuf = gHvInputBuffers;
340 // block below copy/pasted from libpd, except
341 // 16 has been replaced with gDigitalSigInChannelsInUse
342 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
343 unsigned int digitalFrame = audioFrameBase + j;
344 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstDigitalChannel;
345 k < gDigitalSigInChannelsInUse; ++k, p1 += gLibpdBlockSize) {
346 if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate
347 *p1 = digitalRead(context, digitalFrame, k);
348 }
349 }
350 }
351 }
352
313 353
314 // replacement for bang~ object 354 // replacement for bang~ object
315 //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b"); 355 //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b");
316 356
317 hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames); 357 hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames);
318 358
319 // Bela digital out 359 // Bela digital out
320 // digital out at signal-rate 360 // Bela digital out at signal-rate
321 // TODO: see note above. 361 if(gDigitalSigOutChannelsInUse > 0)
322 362 {
323 // digital out at message-rate 363 unsigned int j, k;
364 float *p0, *p1;
365 const unsigned int gLibpdBlockSize = context->audioFrames;
366 const unsigned int audioFrameBase = 0;
367 float* gOutBuf = gHvOutputBuffers;
368 // block below copy/pasted from libpd, except
369 // context->digitalChannels has been replaced with gDigitalSigOutChannelsInUse
370 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
371 unsigned int digitalFrame = (audioFrameBase + j);
372 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstDigitalChannel;
373 k < gDigitalSigOutChannelsInUse; k++, p1 += gLibpdBlockSize) {
374 if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate
375 digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5);
376 }
377 }
378 }
379 }
380 // Bela digital out at message-rate
324 dcm.processOutput(context->digital, context->digitalFrames); 381 dcm.processOutput(context->digital, context->digitalFrames);
382
383 // Bela scope
384 if(gScopeChannelsInUse > 0)
385 {
386 unsigned int j, k;
387 float *p0, *p1;
388 const unsigned int gLibpdBlockSize = context->audioFrames;
389 const unsigned int audioFrameBase = 0;
390 float* gOutBuf = gHvOutputBuffers;
391
392 // block below copy/pasted from libpd
393 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
394 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstScopeChannel; k < gScopeChannelsInUse; k++, p1 += gLibpdBlockSize) {
395 gScopeOut[k] = *p1;
396 }
397 scope.log(gScopeOut[0], gScopeOut[1], gScopeOut[2], gScopeOut[3]);
398 }
399 }
325 400
326 // Interleave the output data 401 // Interleave the output data
327 if(gHvOutputBuffers != NULL) { 402 if(gHvOutputBuffers != NULL) {
328 for(unsigned int n = 0; n < context->audioFrames; n++) { 403 for(unsigned int n = 0; n < context->audioFrames; n++) {
329 404
352 hv_bbb_free(gHeavyContext); 427 hv_bbb_free(gHeavyContext);
353 if(gHvInputBuffers != NULL) 428 if(gHvInputBuffers != NULL)
354 free(gHvInputBuffers); 429 free(gHvInputBuffers);
355 if(gHvOutputBuffers != NULL) 430 if(gHvOutputBuffers != NULL)
356 free(gHvOutputBuffers); 431 free(gHvOutputBuffers);
357 432 delete[] gScopeOut;
358 } 433 }