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