comparison examples/basic_libpd/render.cpp @ 345:0e1e0dfe24c5 prerelease

Added embryonal support for digital messages with libpd. TODO: test it, only process used channels, add defines. It is quite CPU-intensive
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 07 Jun 2016 03:40:01 +0100
parents 4823ee13bcac
children db1e024858b0
comparison
equal deleted inserted replaced
344:1c35a5d0ce32 345:0e1e0dfe24c5
4 * Created on: Oct 24, 2014 4 * Created on: Oct 24, 2014
5 * Author: parallels 5 * Author: parallels
6 */ 6 */
7 7
8 #include <Bela.h> 8 #include <Bela.h>
9 #include <DigitalToMessage.h>
9 #include <cmath> 10 #include <cmath>
10 #include <Utilities.h> 11 #include <Utilities.h>
11 #include <I2c_Codec.h> 12 #include <I2c_Codec.h>
12 #include <PRU.h> 13 #include <PRU.h>
13 #include <stdio.h> 14 #include <stdio.h>
14 #include "z_libpd.h" 15 #include "z_libpd.h"
15 #include "z_queued.h" 16 #include "z_queued.h"
16 #include "s_stuff.h" 17 #include "s_stuff.h"
17 #include <UdpServer.h> 18 #include <UdpServer.h>
18 #include <Midi.h> 19 #include <Midi.h>
19 20 //extern t_sample* sys_soundin;
20 // if you are 100% sure of what value that was used to compile libpd/puredata, then 21 //extern t_sample* sys_soundout;
21 // you could define this, instead of getting it at runtime. It has proved to give some 0.3% 22 // if you are 100% sure of what value was used to compile libpd/puredata, then
23 // you could #define this 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). 24 // performance boost when it is 8 (thanks to vectorize optimizations I guess).
23 unsigned int gLibpdBlockSize;
24
25 unsigned int gChannelsInUse = 10;
26 int gBufLength; 25 int gBufLength;
27 26
28 float* gInBuf; 27 float* gInBuf;
29 float* gOutBuf; 28 float* gOutBuf;
30 29
51 AuxiliaryTask libpdProcessMessageQueueTask; 50 AuxiliaryTask libpdProcessMessageQueueTask;
52 AuxiliaryTask libpdProcessMidiQueueTask; 51 AuxiliaryTask libpdProcessMidiQueueTask;
53 Midi midi; 52 Midi midi;
54 //UdpServer udpServer; 53 //UdpServer udpServer;
55 54
55 void sendDigitalMessage(bool state, unsigned int delay, void* receiverName){
56 libpd_float((char*)receiverName, (float)state);
57 // rt_printf("%s: %d\n", (char*)receiverName, state);
58 }
59 char receiverNames[16][21]={
60 {"bela_digitalIn11"},{"bela_digitalIn12"},{"bela_digitalIn13"},{"bela_digitalIn14"},{"bela_digitalIn15"},
61 {"bela_digitalIn16"},{"bela_digitalIn17"},{"bela_digitalIn18"},{"bela_digitalIn19"},{"bela_digitalIn20"},
62 {"bela_digitalIn21"},{"bela_digitalIn22"},{"bela_digitalIn23"},{"bela_digitalIn24"},{"bela_digitalIn25"},
63 {"bela_digitalIn26"}
64 };
65
66 static DigitalToMessage** dtm;
67 static unsigned int analogChannelsInUse;
68 static unsigned int gLibpdBlockSize;
69 static unsigned int gChannelsInUse = 26;
70
56 bool setup(BelaContext *context, void *userData) 71 bool setup(BelaContext *context, void *userData)
57 { 72 {
73 analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels - context->digitalChannels);
74 dtm = new DigitalToMessage* [context->digitalChannels];
75 if(context->digitalChannels > 0){
76 for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){
77 dtm[ch] = new DigitalToMessage;
78 dtm[ch]->setCallback(sendDigitalMessage, receiverNames[ch]);
79 pinMode(context, 0, ch, OUTPUT);
80 }
81 }
58 midi.readFrom(0); 82 midi.readFrom(0);
59 midi.writeTo(0); 83 midi.writeTo(0);
60 #ifdef PARSE_MIDI 84 #ifdef PARSE_MIDI
61 midi.enableParser(true); 85 midi.enableParser(true);
62 #else 86 #else
63 midi.enableParser(false); 87 midi.enableParser(false);
64 #endif /* PARSE_MIDI */ 88 #endif /* PARSE_MIDI */
65 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse); 89 // gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse);
66 // udpServer.bindToPort(1234); 90 // udpServer.bindToPort(1234);
67 91
68 gLibpdBlockSize = libpd_blocksize(); 92 gLibpdBlockSize = libpd_blocksize();
69 // check that we are not running with a blocksize smaller than gLibPdBlockSize 93 // check that we are not running with a blocksize smaller than gLibPdBlockSize
70 // it would still work, but the load would be executed unevenly between calls to render 94 // it would still work, but the load would be executed unevenly between calls to render
103 127
104 // render() is called regularly at the highest priority by the audio engine. 128 // render() is called regularly at the highest priority by the audio engine.
105 // Input and output are given from the audio hardware and the other 129 // Input and output are given from the audio hardware and the other
106 // ADCs and DACs (if available). If only audio is available, numMatrixFrames 130 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
107 // will be 0. 131 // will be 0.
108 BelaContext *c; 132
109 void render(BelaContext *context, void *userData) 133 void render(BelaContext *context, void *userData)
110 { 134 {
111 int num; 135 int num;
112 // the safest thread-safe option to handle MIDI input is to process the MIDI buffer 136 // the safest thread-safe option to handle MIDI input is to process the MIDI buffer
113 // from the audio thread. 137 // from the audio thread.
190 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers 214 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers
191 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably 215 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably
192 * do not need the for loops before and after libpd_process_float, so you can save quite some 216 * do not need the for loops before and after libpd_process_float, so you can save quite some
193 * memory operations. 217 * memory operations.
194 */ 218 */
195 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels);
196 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; 219 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize;
197 for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){ 220 for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){
198 unsigned int audioOutFrameBase = gLibpdBlockSize * tick; 221 unsigned int audioFrameBase = gLibpdBlockSize * tick;
199 unsigned int j; 222 unsigned int j;
200 unsigned int k; 223 unsigned int k;
201 float* p0; 224 float* p0;
202 float* p1; 225 float* p1;
203 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 226 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
204 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { 227 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) {
205 *p1 = audioRead(context, audioOutFrameBase + j, k); 228 *p1 = audioRead(context, audioFrameBase + j, k);
206 } 229 }
207 } 230 }
208 // then analogs 231 // then analogs
209 // this loop resamples by ZOH, as needed, using m 232 // this loop resamples by ZOH, as needed, using m
210 if(context->analogChannels == 8 ){ //hold the value for two frames 233 if(context->analogChannels == 8 ){ //hold the value for two frames
211 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 234 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
212 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 235 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) {
213 unsigned int analogFrame = (audioOutFrameBase + j) / 2; 236 unsigned int analogFrame = (audioFrameBase + j) / 2;
214 *p1 = analogRead(context, analogFrame, k); 237 *p1 = analogRead(context, analogFrame, k);
215 } 238 }
216 } 239 }
217 } else if(context->analogChannels == 4){ //write every frame 240 } else if(context->analogChannels == 4){ //write every frame
218 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 241 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
219 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 242 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) {
220 unsigned int analogFrame = audioOutFrameBase + j; 243 unsigned int analogFrame = audioFrameBase + j;
221 *p1 = analogRead(context, analogFrame, k); 244 *p1 = analogRead(context, analogFrame, k);
222 } 245 }
223 } 246 }
224 } else if(context->analogChannels == 2){ //drop every other frame 247 } else if(context->analogChannels == 2){ //drop every other frame
225 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { 248 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) {
226 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 249 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) {
227 unsigned int analogFrame = (audioOutFrameBase + j) * 2; 250 unsigned int analogFrame = (audioFrameBase + j) * 2;
228 *p1 = analogRead(context, analogFrame, k); 251 *p1 = analogRead(context, analogFrame, k);
229 } 252 }
230 } 253 }
231 } 254 }
255
256 //then digital
257 //TODO: in multiple places we assume that the number of digitals is same as number of audio
258 for(unsigned int n = 0; n < context->digitalChannels; ++n){
259 // TODO: note that we consider only the first sample of the block
260 // considering all of them is notably more expensive
261 // TODO: only process the channels marked as such
262 dtm[n]->process(n + 16, &context->digital[audioFrameBase], 1);
263 }
264
232 libpd_process_sys(); // process the block 265 libpd_process_sys(); // process the block
266
267 //digital
268 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
269 unsigned int digitalFrame = (audioFrameBase + j);
270 for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8);
271 k < context->digitalChannels; k++, p1 += gLibpdBlockSize) {
272 // TODO: only process the channels marked as such
273 digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5);
274 }
275 }
276 //audio
233 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { 277 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) {
234 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { 278 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) {
235 audioWrite(context, audioOutFrameBase + j, k, *p1); 279 audioWrite(context, audioFrameBase + j, k, *p1);
236 } 280 }
237 } 281 }
282 //analog
238 if(context->analogChannels == 8){ 283 if(context->analogChannels == 8){
239 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames 284 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames
240 unsigned int analogFrame = (audioOutFrameBase + j) / 2; 285 unsigned int analogFrame = (audioFrameBase + j) / 2;
241 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 286 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) {
242 analogWrite(context, analogFrame, k, *p1); 287 analogWriteOnce(context, analogFrame, k, *p1);
243 } 288 }
244 } 289 }
245 } else if(context->analogChannels == 4){ //write every frame 290 } else if(context->analogChannels == 4){ //write every frame
246 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { 291 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) {
247 unsigned int analogFrame = (audioOutFrameBase + j); 292 unsigned int analogFrame = (audioFrameBase + j);
248 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 293 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) {
249 analogWrite(context, analogFrame, k, *p1); 294 analogWriteOnce(context, analogFrame, k, *p1);
250 } 295 }
251 } 296 }
252 } else if(context->analogChannels == 2){ //write every frame twice 297 } else if(context->analogChannels == 2){ //write every frame twice
253 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { 298 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) {
254 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { 299 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) {
255 int analogFrame = audioOutFrameBase * 2 + j * 2; 300 int analogFrame = audioFrameBase * 2 + j * 2;
256 analogWrite(context, analogFrame, k, *p1); 301 analogWriteOnce(context, analogFrame, k, *p1);
257 analogWrite(context, analogFrame + 1, k, *p1); 302 analogWriteOnce(context, analogFrame + 1, k, *p1);
258 } 303 }
259 } 304 }
260 } 305 }
261 } 306 }
262 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask); 307 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask);
267 // Release any resources that were allocated in setup(). 312 // Release any resources that were allocated in setup().
268 313
269 void cleanup(BelaContext *context, void *userData) 314 void cleanup(BelaContext *context, void *userData)
270 { 315 {
271 libpd_queued_release(); 316 libpd_queued_release();
272 } 317 delete[] dtm;
318 }