Mercurial > hg > beaglert
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 } |