Mercurial > hg > beaglert
comparison examples/basic_libpd/render.cpp @ 343:4823ee13bcac prerelease
basic_libpd now populates pd's audio buffers directly. Updated libpd.so binary. This required an API change with respect to standard libpdAPI because for some strange reason, accessing sys_audioin and sys_audioout directly from the render.cpp file would return invalid values.
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Mon, 06 Jun 2016 15:15:15 +0100 |
parents | 860c42b3830e |
children | 0e1e0dfe24c5 |
comparison
equal
deleted
inserted
replaced
342:860c42b3830e | 343:4823ee13bcac |
---|---|
15 #include "z_queued.h" | 15 #include "z_queued.h" |
16 #include "s_stuff.h" | 16 #include "s_stuff.h" |
17 #include <UdpServer.h> | 17 #include <UdpServer.h> |
18 #include <Midi.h> | 18 #include <Midi.h> |
19 | 19 |
20 | 20 // if you are 100% sure of what value that was used to compile libpd/puredata, then |
21 // setup() is called once before the audio rendering starts. | 21 // you could define this, instead of getting it at runtime. It has proved to give some 0.3% |
22 // Use it to perform any initialisation and allocation which is dependent | 22 // performance boost when it is 8 (thanks to vectorize optimizations I guess). |
23 // on the period size or sample rate. | 23 unsigned int gLibpdBlockSize; |
24 // | |
25 // userData holds an opaque pointer to a data structure that was passed | |
26 // in from the call to initAudio(). | |
27 // | |
28 // Return true on success; returning false halts the program. | |
29 unsigned int gLibpdBlockSize; //make sure this matches the one used to compile libpd | |
30 | 24 |
31 unsigned int gChannelsInUse = 10; | 25 unsigned int gChannelsInUse = 10; |
32 int gBufLength; | 26 int gBufLength; |
33 | 27 |
34 float* gInBuf; | 28 float* gInBuf; |
198 * do not need the for loops before and after libpd_process_float, so you can save quite some | 192 * do not need the for loops before and after libpd_process_float, so you can save quite some |
199 * memory operations. | 193 * memory operations. |
200 */ | 194 */ |
201 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels); | 195 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels); |
202 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; | 196 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; |
203 for(unsigned int j = 0; j < numberOfPdBlocksToProcess; ++j){ | 197 for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){ |
204 unsigned int inW = 0; | 198 unsigned int audioOutFrameBase = gLibpdBlockSize * tick; |
205 unsigned int outR = 0; | 199 unsigned int j; |
206 | 200 unsigned int k; |
207 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved | 201 float* p0; |
208 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ //first two channels are audio | 202 float* p1; |
209 gInBuf[inW++] = audioRead(context, n, ch); | 203 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { |
210 } | 204 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { |
211 // then analogs | 205 *p1 = audioRead(context, audioOutFrameBase + j, k); |
212 // this loop resamples by ZOH, as needed, using m | 206 } |
213 if(context->analogChannels == 8 ){ //hold the value for two frames | 207 } |
214 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | 208 // then analogs |
215 gInBuf[inW++] = analogRead(context, n/2, analogCh); // n/2 wil be the same for n and n+1 when n is even | 209 // this loop resamples by ZOH, as needed, using m |
216 } | 210 if(context->analogChannels == 8 ){ //hold the value for two frames |
217 } else if(context->analogChannels == 4){ //write every frame | 211 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { |
218 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | 212 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { |
219 gInBuf[inW++] = analogRead(context, n, analogCh); | 213 unsigned int analogFrame = (audioOutFrameBase + j) / 2; |
220 } | 214 *p1 = analogRead(context, analogFrame, k); |
221 } else if(context->analogChannels == 2){ //drop every other frame | 215 } |
222 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | 216 } |
223 gInBuf[inW++] = analogRead(context, n*2, analogCh); | 217 } else if(context->analogChannels == 4){ //write every frame |
218 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { | |
219 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { | |
220 unsigned int analogFrame = audioOutFrameBase + j; | |
221 *p1 = analogRead(context, analogFrame, k); | |
222 } | |
223 } | |
224 } else if(context->analogChannels == 2){ //drop every other frame | |
225 for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { | |
226 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { | |
227 unsigned int analogFrame = (audioOutFrameBase + j) * 2; | |
228 *p1 = analogRead(context, analogFrame, k); | |
224 } | 229 } |
225 } | 230 } |
226 } | 231 } |
227 libpd_process_sys(); // process the block | 232 libpd_process_sys(); // process the block |
228 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved | 233 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { |
229 unsigned int outAudioFrame = 0; | 234 for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { |
230 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ | 235 audioWrite(context, audioOutFrameBase + j, k, *p1); |
231 audioWrite(context, outAudioFrame, ch, gOutBuf[outR++]); | 236 } |
232 } | 237 } |
233 //and analogs | 238 if(context->analogChannels == 8){ |
234 if(context->analogChannels == 8){ | 239 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames |
235 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | 240 unsigned int analogFrame = (audioOutFrameBase + j) / 2; |
236 float analogOut = gOutBuf[outR++]; | 241 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { |
237 if((n&1) == 0){//write every two frames | 242 analogWrite(context, analogFrame, k, *p1); |
238 analogWrite(context, outAudioFrame/2, analogCh, analogOut); | 243 } |
239 } else { | 244 } |
240 // discard this sample | 245 } else if(context->analogChannels == 4){ //write every frame |
241 } | 246 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { |
242 } | 247 unsigned int analogFrame = (audioOutFrameBase + j); |
243 } else if(context->analogChannels == 4){ //write every frame | 248 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { |
244 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | 249 analogWrite(context, analogFrame, k, *p1); |
245 float analogOut = gOutBuf[outR++]; | 250 } |
246 analogWrite(context, outAudioFrame, analogCh, analogOut); | 251 } |
247 } | 252 } else if(context->analogChannels == 2){ //write every frame twice |
248 } else if(context->analogChannels == 2){ //write twice every frame | 253 for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { |
249 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | 254 for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { |
250 float analogOut = gOutBuf[outR++]; | 255 int analogFrame = audioOutFrameBase * 2 + j * 2; |
251 analogWrite(context, 2*outAudioFrame, analogCh, analogOut); | 256 analogWrite(context, analogFrame, k, *p1); |
252 analogWrite(context, 2*outAudioFrame + 1, analogCh, analogOut); | 257 analogWrite(context, analogFrame + 1, k, *p1); |
253 } | 258 } |
254 } | 259 } |
255 } | 260 } |
256 } | 261 } |
257 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask); | 262 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask); |
262 // Release any resources that were allocated in setup(). | 267 // Release any resources that were allocated in setup(). |
263 | 268 |
264 void cleanup(BelaContext *context, void *userData) | 269 void cleanup(BelaContext *context, void *userData) |
265 { | 270 { |
266 libpd_queued_release(); | 271 libpd_queued_release(); |
267 // free(gInBuf); | 272 } |
268 // free(gOutBuf); | |
269 } |