comparison examples/basic_libpd/render.cpp @ 341:7af9c5be3434 prerelease

libpd: using smaller blocksizes for processing, so that events can be scheduled more accurately
author Giulio Moro <giuliomoro@yahoo.it>
date Mon, 06 Jun 2016 03:31:22 +0100
parents 69d86429a1cf
children 860c42b3830e
comparison
equal deleted inserted replaced
340:69d86429a1cf 341:7af9c5be3434
116 // will be 0. 116 // will be 0.
117 BelaContext *c; 117 BelaContext *c;
118 void render(BelaContext *context, void *userData) 118 void render(BelaContext *context, void *userData)
119 { 119 {
120 int num; 120 int num;
121 // the safest thread-safe option to handle MIDI input is to process the MIDI buffer
122 // from the audio thread.
121 #ifdef PARSE_MIDI 123 #ifdef PARSE_MIDI
122 while((num = midi.getParser()->numAvailableMessages()) > 0){ 124 while((num = midi.getParser()->numAvailableMessages()) > 0){
123 static MidiChannelMessage message; 125 static MidiChannelMessage message;
124 message = midi.getParser()->getNextChannelMessage(); 126 message = midi.getParser()->getNextChannelMessage();
125 // message.prettyPrint(); // use this to print beautified message (channel, data bytes) 127 //message.prettyPrint(); // use this to print beautified message (channel, data bytes)
126 switch(message.getType()){ 128 switch(message.getType()){
127 case kmmNoteOn: 129 case kmmNoteOn:
128 { 130 {
129 int noteNumber = message.getDataByte(0); 131 int noteNumber = message.getDataByte(0);
130 int velocity = message.getDataByte(1); 132 int velocity = message.getDataByte(1);
191 while((input = midi.getInput()) >= 0){ 193 while((input = midi.getInput()) >= 0){
192 libpd_midibyte(0, input); 194 libpd_midibyte(0, input);
193 } 195 }
194 #endif /* PARSE_MIDI */ 196 #endif /* PARSE_MIDI */
195 197
196 static unsigned int inW = 0; 198 unsigned int inW = 0;
197 static unsigned int outR = 0; 199 unsigned int outR = 0;
198 /* 200 /*
199 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers 201 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers
200 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably 202 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably
201 * do not need the for loops before and after libpd_process_float, so you can save quite some 203 * do not need the for loops before and after libpd_process_float, so you can save quite some
202 * memory operations. 204 * memory operations.
203 */ 205 */
204 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels); 206 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels);
207 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize;
205 // rt_printf("channelsInUse: %d, analogChannels in Use: %d\n", gChannelsInUse, analogChannelsInUse); 208 // rt_printf("channelsInUse: %d, analogChannels in Use: %d\n", gChannelsInUse, analogChannelsInUse);
206 for(unsigned int n = 0; n < context->audioFrames; ++n){ //pd buffers are interleaved 209 for(unsigned int j = 0; j < numberOfPdBlocksToProcess; ++j){
207 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ //first two channels are audio 210 int oldInW = inW;
208 gInBuf[inW++] = audioRead(context, n, ch); 211 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved
212 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ //first two channels are audio
213 gInBuf[inW++] = audioRead(context, n, ch);
214 }
215 // then analogs
216 // this loop resamples by ZOH, as needed, using m
217 if(context->analogChannels == 8 ){ //hold the value for two frames
218 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
219 gInBuf[inW++] = analogRead(context, n/2, analogCh); // n/2 wil be the same for n and n+1 when n is even
220 }
221 } else if(context->analogChannels == 4){ //write every frame
222 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
223 gInBuf[inW++] = analogRead(context, n, analogCh);
224 }
225 } else if(context->analogChannels == 2){ //drop every other frame
226 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
227 gInBuf[inW++] = analogRead(context, n*2, analogCh);
228 }
229 }
209 } 230 }
210 // then analogs
211 // this loop resamples by ZOH, as needed, using m
212 if(context->analogChannels == 8 ){ //hold the value for two frames
213 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
214 gInBuf[inW++] = analogRead(context, n/2, analogCh); // n/2 wil be the same for n and n+1 when n is even
215 }
216 } else if(context->analogChannels == 4){ //write every frame
217 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
218 gInBuf[inW++] = analogRead(context, n, analogCh);
219 }
220 } else if(context->analogChannels == 2){ //drop every other frame
221 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
222 gInBuf[inW++] = analogRead(context, n*2, analogCh);
223 }
224 }
225 if(inW == gBufLength * gChannelsInUse){
226 inW = 0;
227 }
228 }
229 // rt_printf("inW %d\n", inW);
230 if(inW == 0){ //if the buffer is full, process it
231 static int numberOfPdBlocksToProcess = gBufLength/gLibpdBlockSize;
232 // TODO: see if we can rewrite libpd_process_float so that it takes a buffer 231 // TODO: see if we can rewrite libpd_process_float so that it takes a buffer
233 // of interleaved channels of arbitrary length rather than a series of 232 // of interleaved channels of arbitrary length rather than a series of
234 // stacked buffers of size gLibPdBlockSize as it currently does. 233 // stacked buffers of size gLibPdBlockSize as it currently does.
235 libpd_process_float(numberOfPdBlocksToProcess, gInBuf, gOutBuf); 234 // This would allow to use the buffers as they are rather than having to copy them
236 outR = 0; // reset the read pointer. NOTE: hopefully this is needed only the first time 235 libpd_process_float(1, &gInBuf[oldInW], &gOutBuf[oldInW]);
237 } 236 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved
238 237 unsigned int outAudioFrame = n + j * gLibpdBlockSize;
239 for(unsigned int n = 0; n < context->audioFrames; n++){ //pd buffers are interleaved 238 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){
240 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ 239 audioWrite(context, outAudioFrame, ch, gOutBuf[outR++]);
241 audioWrite(context, n, ch, gOutBuf[outR++]); 240 }
241 //and analogs
242 if(context->analogChannels == 8){
243 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
244 float analogOut = gOutBuf[outR++];
245 if((n&1) == 0){//write every two frames
246 analogWrite(context, outAudioFrame/2, analogCh, analogOut);
247 } else {
248 // discard this sample
249 }
250 }
251 } else if(context->analogChannels == 4){ //write every frame
252 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
253 float analogOut = gOutBuf[outR++];
254 analogWrite(context, outAudioFrame, analogCh, analogOut);
255 }
256 } else if(context->analogChannels == 2){ //write twice every frame
257 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
258 float analogOut = gOutBuf[outR++];
259 analogWrite(context, 2*outAudioFrame, analogCh, analogOut);
260 analogWrite(context, 2*outAudioFrame + 1, analogCh, analogOut);
261 }
262 }
242 } 263 }
243 //and analogs 264 }
244 if(context->analogChannels == 8){
245 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
246 float analogOut = gOutBuf[outR++];
247 if((n&1) == 0){//write every two frames
248 analogWrite(context, n/2, analogCh, analogOut);
249 } else {
250 // discard this sample
251 }
252 }
253 } else if(context->analogChannels == 4){ //write every frame
254 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
255 float analogOut = gOutBuf[outR++];
256 analogWrite(context, n, analogCh, analogOut);
257 }
258 } else if(context->analogChannels == 2){ //write twice every frame
259 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
260 float analogOut = gOutBuf[outR++];
261 analogWrite(context, 2*n, analogCh, analogOut);
262 analogWrite(context, 2*n + 1, analogCh, analogOut);
263 }
264 }
265 if(outR == gBufLength * gChannelsInUse){
266 outR = 0;
267 }
268 }
269 // rt_printf("outR %d, analogChannelsInUse %d, channelsInUse %d\n",
270 // outR , analogChannelsInUse, gChannelsInUse);
271 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask); 265 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask);
272 Bela_scheduleAuxiliaryTask(libpdProcessMessageQueueTask); 266 Bela_scheduleAuxiliaryTask(libpdProcessMessageQueueTask);
273 } 267 }
274 268
275 // cleanup() is called once at the end, after the audio has stopped. 269 // cleanup() is called once at the end, after the audio has stopped.