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