comparison core/default_libpd_render.cpp @ 474:efc9a9f8e63d prerelease

Libpd added scope support and example
author Giulio Moro <giuliomoro@yahoo.it>
date Mon, 20 Jun 2016 20:38:46 +0100
parents 5a936f8e9447
children 838a4a4a8580
comparison
equal deleted inserted replaced
473:2a0b468ce1dd 474:efc9a9f8e63d
13 #include <stdio.h> 13 #include <stdio.h>
14 #include <libpd/z_libpd.h> 14 #include <libpd/z_libpd.h>
15 #include <libpd/s_stuff.h> 15 #include <libpd/s_stuff.h>
16 #include <UdpServer.h> 16 #include <UdpServer.h>
17 #include <Midi.h> 17 #include <Midi.h>
18 //extern t_sample* sys_soundin; 18 #include <Scope.h>
19 //extern t_sample* sys_soundout; 19
20 // if you are 100% sure of what value was used to compile libpd/puredata, then 20 // if you are 100% sure of what value was used to compile libpd/puredata, then
21 // you could #define this instead of getting it at runtime. It has proved to give some 0.3% 21 // you could #define gBufLength instead of getting it at runtime. It has proved to give some 0.3%
22 // performance boost when it is 8 (thanks to vectorize optimizations I guess). 22 // performance boost when it is 8 (thanks to vectorize optimizations I guess).
23 int gBufLength; 23 int gBufLength;
24 24
25 float* gInBuf; 25 float* gInBuf;
26 float* gOutBuf; 26 float* gOutBuf;
31 31
32 void Bela_printHook(const char *recv){ 32 void Bela_printHook(const char *recv){
33 rt_printf("%s", recv); 33 rt_printf("%s", recv);
34 } 34 }
35 35
36 //TODO: remove this function
36 void libpdReadFilesLoop(){ 37 void libpdReadFilesLoop(){
37 while(!gShouldStop){ 38 while(!gShouldStop){
38 // check for modified sockets/file descriptors 39 // check for modified sockets/file descriptors
39 // (libpd would normally do this every block WITHIN the audio thread) 40 // (libpd would normally do this every block WITHIN the audio thread)
40 // not sure if this is thread-safe at the moment 41 // not sure if this is thread-safe at the moment
104 if(source[prefixLength + 1] != 0){ 105 if(source[prefixLength + 1] != 0){
105 // quickly convert the suffix to integer, assuming they are numbers, avoiding to call atoi 106 // quickly convert the suffix to integer, assuming they are numbers, avoiding to call atoi
106 int receiver = ((source[prefixLength] - 48) * 10); 107 int receiver = ((source[prefixLength] - 48) * 10);
107 receiver += (source[prefixLength+1] - 48); 108 receiver += (source[prefixLength+1] - 48);
108 unsigned int channel = receiver - 11; // go back to the actual Bela digital channel number 109 unsigned int channel = receiver - 11; // go back to the actual Bela digital channel number
109 if(channel >= 0 && channel < 16){ //16 is the hardcoded value for the number of digital channels 110 if(channel < 16){ //16 is the hardcoded value for the number of digital channels
110 dcm.setValue(channel, value); 111 dcm.setValue(channel, value);
111 } 112 }
112 } 113 }
113 } 114 }
114 } 115 }
119 {"bela_digitalIn16"},{"bela_digitalIn17"},{"bela_digitalIn18"},{"bela_digitalIn19"},{"bela_digitalIn20"}, 120 {"bela_digitalIn16"},{"bela_digitalIn17"},{"bela_digitalIn18"},{"bela_digitalIn19"},{"bela_digitalIn20"},
120 {"bela_digitalIn21"},{"bela_digitalIn22"},{"bela_digitalIn23"},{"bela_digitalIn24"},{"bela_digitalIn25"}, 121 {"bela_digitalIn21"},{"bela_digitalIn22"},{"bela_digitalIn23"},{"bela_digitalIn24"},{"bela_digitalIn25"},
121 {"bela_digitalIn26"} 122 {"bela_digitalIn26"}
122 }; 123 };
123 124
124 static unsigned int analogChannelsInUse; 125 static unsigned int gAnalogChannelsInUse;
125 static unsigned int gLibpdBlockSize; 126 static unsigned int gLibpdBlockSize;
126 static unsigned int gChannelsInUse = 26; 127 // 2 audio + (up to)8 analog + (up to) 16 digital + 4 scope outputs
127 128 static const unsigned int gChannelsInUse = 30;
129 static const unsigned int gFirstAudioChannel = 0;
130 static const unsigned int gFirstAnalogChannel = 2;
131 static const unsigned int gFirstDigitalChannel = 10;
132 static const unsigned int gFirstScopeChannel = 26;
133
134 Scope scope;
135 unsigned int gScopeChannels = 4;
128 bool setup(BelaContext *context, void *userData) 136 bool setup(BelaContext *context, void *userData)
129 { 137 {
138 scope.setup(gScopeChannels, context->audioSampleRate);
139
130 // Check first of all if file exists. Will actually open it later. 140 // Check first of all if file exists. Will actually open it later.
131 char file[] = "_main.pd"; 141 char file[] = "_main.pd";
132 char folder[] = "./"; 142 char folder[] = "./";
133 unsigned int strSize = strlen(file) + strlen(folder) + 1; 143 unsigned int strSize = strlen(file) + strlen(folder) + 1;
134 char* str = (char*)malloc(sizeof(char) * strSize); 144 char* str = (char*)malloc(sizeof(char) * strSize);
136 if(access(str, F_OK) == -1 ) { 146 if(access(str, F_OK) == -1 ) {
137 printf("Error file %s/%s not found. The %s file should be your main patch.\n", folder, file, file); 147 printf("Error file %s/%s not found. The %s file should be your main patch.\n", folder, file, file);
138 return false; 148 return false;
139 } 149 }
140 dcm.setCallback(sendDigitalMessage); 150 dcm.setCallback(sendDigitalMessage);
141 analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels - context->digitalChannels); 151 gAnalogChannelsInUse = context->analogChannels;
142 if(context->digitalChannels > 0){ 152 if(context->digitalChannels > 0){
143 for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){ 153 for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){
144 dcm.setCallbackArgument(ch, receiverNames[ch]); 154 dcm.setCallbackArgument(ch, receiverNames[ch]);
145 } 155 }
146 } 156 }
149 #ifdef PARSE_MIDI 159 #ifdef PARSE_MIDI
150 midi.enableParser(true); 160 midi.enableParser(true);
151 #else 161 #else
152 midi.enableParser(false); 162 midi.enableParser(false);
153 #endif /* PARSE_MIDI */ 163 #endif /* PARSE_MIDI */
154 // gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse);
155 // udpServer.bindToPort(1234); 164 // udpServer.bindToPort(1234);
156 165
157 gLibpdBlockSize = libpd_blocksize(); 166 gLibpdBlockSize = libpd_blocksize();
158 // check that we are not running with a blocksize smaller than gLibPdBlockSize 167 // check that we are not running with a blocksize smaller than gLibPdBlockSize
159 // it would still work, but the load would be executed unevenly between calls to render 168 // We could still make it work, but the load would be executed unevenly between calls to render
160 if(context->audioFrames < gLibpdBlockSize){ 169 if(context->audioFrames < gLibpdBlockSize){
161 fprintf(stderr, "Error: minimum block size must be %d\n", gLibpdBlockSize); 170 fprintf(stderr, "Error: minimum block size must be %d\n", gLibpdBlockSize);
162 return false; 171 return false;
163 } 172 }
164 // set hooks before calling libpd_init 173 // set hooks before calling libpd_init
297 } 306 }
298 #endif /* PARSE_MIDI */ 307 #endif /* PARSE_MIDI */
299 308
300 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; 309 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize;
301 310
302 // these are reset at every audio callback. Persistence across audio callbacks
303 // is handled by the core code.
304 // setDataOut = 0;
305 // clearDataOut = 0;
306
307 for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){ 311 for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){
308 unsigned int audioFrameBase = gLibpdBlockSize * tick; 312 unsigned int audioFrameBase = gLibpdBlockSize * tick;
309 unsigned int j; 313 unsigned int j;
310 unsigned int k; 314 unsigned int k;
311 float* p0; 315 float* p0;
317 } 321 }
318 // then analogs 322 // then analogs
319 // this loop resamples by ZOH, as needed, using m 323 // this loop resamples by ZOH, as needed, using m
320 if(context->analogChannels == 8 ){ //hold the value for two frames 324 if(context->analogChannels == 8 ){ //hold the value for two frames
321 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 325 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
322 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 326 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstAnalogChannel; k < gAnalogChannelsInUse; ++k, p1 += gLibpdBlockSize) {
323 unsigned int analogFrame = (audioFrameBase + j) / 2; 327 unsigned int analogFrame = (audioFrameBase + j) / 2;
324 *p1 = analogRead(context, analogFrame, k); 328 *p1 = analogRead(context, analogFrame, k);
325 } 329 }
326 } 330 }
327 } else if(context->analogChannels == 4){ //write every frame 331 } else if(context->analogChannels == 4){ //write every frame
328 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 332 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
329 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 333 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstAnalogChannel; k < gAnalogChannelsInUse; ++k, p1 += gLibpdBlockSize) {
330 unsigned int analogFrame = audioFrameBase + j; 334 unsigned int analogFrame = audioFrameBase + j;
331 *p1 = analogRead(context, analogFrame, k); 335 *p1 = analogRead(context, analogFrame, k);
332 } 336 }
333 } 337 }
334 } else if(context->analogChannels == 2){ //drop every other frame 338 } else if(context->analogChannels == 2){ //drop every other frame
335 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 339 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
336 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 340 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstAnalogChannel; k < gAnalogChannelsInUse; ++k, p1 += gLibpdBlockSize) {
337 unsigned int analogFrame = (audioFrameBase + j) * 2; 341 unsigned int analogFrame = (audioFrameBase + j) * 2;
338 *p1 = analogRead(context, analogFrame, k); 342 *p1 = analogRead(context, analogFrame, k);
339 } 343 }
340 } 344 }
341 } 345 }
346 dcm.processInput(&context->digital[audioFrameBase], gLibpdBlockSize); 350 dcm.processInput(&context->digital[audioFrameBase], gLibpdBlockSize);
347 351
348 // digital in at signal-rate 352 // digital in at signal-rate
349 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 353 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
350 unsigned int digitalFrame = audioFrameBase + j; 354 unsigned int digitalFrame = audioFrameBase + j;
351 for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8); 355 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstDigitalChannel;
352 k < 16; ++k, p1 += gLibpdBlockSize) { 356 k < 16; ++k, p1 += gLibpdBlockSize) {
353 if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate 357 if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate
354 *p1 = digitalRead(context, digitalFrame, k); 358 *p1 = digitalRead(context, digitalFrame, k);
355 } 359 }
356 } 360 }
360 364
361 //digital out 365 //digital out
362 // digital out at signal-rate 366 // digital out at signal-rate
363 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { 367 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
364 unsigned int digitalFrame = (audioFrameBase + j); 368 unsigned int digitalFrame = (audioFrameBase + j);
365 for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8); 369 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstDigitalChannel;
366 k < context->digitalChannels; k++, p1 += gLibpdBlockSize) { 370 k < context->digitalChannels; k++, p1 += gLibpdBlockSize) {
367 if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate 371 if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate
368 digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5); 372 digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5);
369 } 373 }
370 } 374 }
377 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { 381 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) {
378 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { 382 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) {
379 audioWrite(context, audioFrameBase + j, k, *p1); 383 audioWrite(context, audioFrameBase + j, k, *p1);
380 } 384 }
381 } 385 }
386 //scope
387 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
388 float scopeOut[gScopeChannels]={0};
389 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstScopeChannel; k < gScopeChannels; k++, p1 += gLibpdBlockSize) {
390 scopeOut[k] = *p1;
391 }
392 scope.log(scopeOut[0], scopeOut[1], scopeOut[2], scopeOut[3]);
393 }
394
382 395
383 //analog 396 //analog
384 if(context->analogChannels == 8){ 397 if(context->analogChannels == 8){
385 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames 398 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames
386 unsigned int analogFrame = (audioFrameBase + j) / 2; 399 unsigned int analogFrame = (audioFrameBase + j) / 2;
387 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 400 for (k = 0, p1 = p0 + gLibpdBlockSize * gFirstAnalogChannel; k < gAnalogChannelsInUse; k++, p1 += gLibpdBlockSize) {
388 analogWriteOnce(context, analogFrame, k, *p1); 401 analogWriteOnce(context, analogFrame, k, *p1);
389 } 402 }
390 } 403 }
391 } else if(context->analogChannels == 4){ //write every frame 404 } else if(context->analogChannels == 4){ //write every frame
392 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { 405 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
393 unsigned int analogFrame = (audioFrameBase + j); 406 unsigned int analogFrame = (audioFrameBase + j);
394 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 407 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < gAnalogChannelsInUse; k++, p1 += gLibpdBlockSize) {
395 analogWriteOnce(context, analogFrame, k, *p1); 408 analogWriteOnce(context, analogFrame, k, *p1);
396 } 409 }
397 } 410 }
398 } else if(context->analogChannels == 2){ //write every frame twice 411 } else if(context->analogChannels == 2){ //write every frame twice
399 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { 412 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) {
400 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 413 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < gAnalogChannelsInUse; k++, p1 += gLibpdBlockSize) {
401 int analogFrame = audioFrameBase * 2 + j * 2; 414 int analogFrame = audioFrameBase * 2 + j * 2;
402 analogWriteOnce(context, analogFrame, k, *p1); 415 analogWriteOnce(context, analogFrame, k, *p1);
403 analogWriteOnce(context, analogFrame + 1, k, *p1); 416 analogWriteOnce(context, analogFrame + 1, k, *p1);
404 } 417 }
405 } 418 }