comparison examples/basic_libpd/render.cpp @ 342:860c42b3830e prerelease

Updated basic_libpd, now slightly more efficient with less memory operations. Requires the API change in libpd operated in libpd:99a2be8
author Giulio Moro <giuliomoro@yahoo.it>
date Mon, 06 Jun 2016 12:21:38 +0100
parents 7af9c5be3434
children 4823ee13bcac
comparison
equal deleted inserted replaced
341:7af9c5be3434 342:860c42b3830e
11 #include <I2c_Codec.h> 11 #include <I2c_Codec.h>
12 #include <PRU.h> 12 #include <PRU.h>
13 #include <stdio.h> 13 #include <stdio.h>
14 #include "z_libpd.h" 14 #include "z_libpd.h"
15 #include "z_queued.h" 15 #include "z_queued.h"
16 #include "s_stuff.h"
16 #include <UdpServer.h> 17 #include <UdpServer.h>
17 #include <Midi.h> 18 #include <Midi.h>
18 19
19 20
20 // setup() is called once before the audio rendering starts. 21 // setup() is called once before the audio rendering starts.
39 40
40 void Bela_printHook(const char *recv){ 41 void Bela_printHook(const char *recv){
41 rt_printf("%s", recv); 42 rt_printf("%s", recv);
42 } 43 }
43 44
44 UdpServer udpServer;
45
46 void libpdReadFilesLoop(){ 45 void libpdReadFilesLoop(){
47 while(!gShouldStop){ 46 while(!gShouldStop){
48 // check for modified sockets/file descriptors 47 // check for modified sockets/file descriptors
49 // (libpd would normally do this every block WITHIN the audio thread) 48 // (libpd would normally do this every block WITHIN the audio thread)
50 // not sure if this is thread-safe at the moment 49 // not sure if this is thread-safe at the moment
56 #define PARSE_MIDI 55 #define PARSE_MIDI
57 AuxiliaryTask libpdReadFilesTask; 56 AuxiliaryTask libpdReadFilesTask;
58 AuxiliaryTask libpdProcessMessageQueueTask; 57 AuxiliaryTask libpdProcessMessageQueueTask;
59 AuxiliaryTask libpdProcessMidiQueueTask; 58 AuxiliaryTask libpdProcessMidiQueueTask;
60 Midi midi; 59 Midi midi;
60 //UdpServer udpServer;
61 61
62 bool setup(BelaContext *context, void *userData) 62 bool setup(BelaContext *context, void *userData)
63 { 63 {
64 midi.readFrom(0); 64 midi.readFrom(0);
65 midi.writeTo(0); 65 midi.writeTo(0);
67 midi.enableParser(true); 67 midi.enableParser(true);
68 #else 68 #else
69 midi.enableParser(false); 69 midi.enableParser(false);
70 #endif /* PARSE_MIDI */ 70 #endif /* PARSE_MIDI */
71 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse); 71 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse);
72 udpServer.bindToPort(1234); 72 // udpServer.bindToPort(1234);
73 73
74 gLibpdBlockSize = libpd_blocksize(); 74 gLibpdBlockSize = libpd_blocksize();
75 // check that we are not running with a blocksize smaller than gLibPdBlockSize 75 // check that we are not running with a blocksize smaller than gLibPdBlockSize
76 // it would still work, but the load would be executed unevenly between calls to render 76 // it would still work, but the load would be executed unevenly between calls to render
77 if(context->audioFrames < gLibpdBlockSize){ 77 if(context->audioFrames < gLibpdBlockSize){
89 libpd_start_message(1); // one entry in list 89 libpd_start_message(1); // one entry in list
90 libpd_add_float(1.0f); 90 libpd_add_float(1.0f);
91 libpd_finish_message("pd", "dsp"); 91 libpd_finish_message("pd", "dsp");
92 92
93 gBufLength = max(gLibpdBlockSize, context->audioFrames); 93 gBufLength = max(gLibpdBlockSize, context->audioFrames);
94 unsigned int bufferSize = sizeof(float)*gChannelsInUse*gBufLength;
95 gInBuf = (float*)malloc(bufferSize);
96 gOutBuf = (float*)malloc(bufferSize);
97 // no need to memset to zero
98 94
99 char file[] = "_main.pd"; 95 char file[] = "_main.pd";
100 char folder[] = "./"; 96 char folder[] = "./";
101 // open patch [; pd open file folder( 97 // open patch [; pd open file folder(
102 libpd_openfile(file, folder); 98 libpd_openfile(file, folder);
103 99 gInBuf = libpd_get_sys_soundin();
100 gOutBuf = libpd_get_sys_soundout();
104 libpdReadFilesTask = Bela_createAuxiliaryTask(libpdReadFilesLoop, 60, "libpdReadFiles"); 101 libpdReadFilesTask = Bela_createAuxiliaryTask(libpdReadFilesLoop, 60, "libpdReadFiles");
105 Bela_scheduleAuxiliaryTask(libpdReadFilesTask); 102 Bela_scheduleAuxiliaryTask(libpdReadFilesTask);
106 103
107 // Higher priority for the midi queue and lower priority for the message queue. Adjust to taste 104 // Higher priority for the midi queue and lower priority for the message queue. Adjust to taste
108 libpdProcessMidiQueueTask = Bela_createAuxiliaryTask(libpd_queued_receive_midi_messages, 80, "libpdProcessMidiQueue"); 105 libpdProcessMidiQueueTask = Bela_createAuxiliaryTask(libpd_queued_receive_midi_messages, 80, "libpdProcessMidiQueue");
193 while((input = midi.getInput()) >= 0){ 190 while((input = midi.getInput()) >= 0){
194 libpd_midibyte(0, input); 191 libpd_midibyte(0, input);
195 } 192 }
196 #endif /* PARSE_MIDI */ 193 #endif /* PARSE_MIDI */
197 194
198 unsigned int inW = 0;
199 unsigned int outR = 0;
200 /* 195 /*
201 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers 196 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers
202 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably 197 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably
203 * do not need the for loops before and after libpd_process_float, so you can save quite some 198 * do not need the for loops before and after libpd_process_float, so you can save quite some
204 * memory operations. 199 * memory operations.
205 */ 200 */
206 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels); 201 static unsigned int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels);
207 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; 202 static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize;
208 // rt_printf("channelsInUse: %d, analogChannels in Use: %d\n", gChannelsInUse, analogChannelsInUse);
209 for(unsigned int j = 0; j < numberOfPdBlocksToProcess; ++j){ 203 for(unsigned int j = 0; j < numberOfPdBlocksToProcess; ++j){
210 int oldInW = inW; 204 unsigned int inW = 0;
205 unsigned int outR = 0;
206
211 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved 207 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 208 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ //first two channels are audio
213 gInBuf[inW++] = audioRead(context, n, ch); 209 gInBuf[inW++] = audioRead(context, n, ch);
214 } 210 }
215 // then analogs 211 // then analogs
226 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ 222 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
227 gInBuf[inW++] = analogRead(context, n*2, analogCh); 223 gInBuf[inW++] = analogRead(context, n*2, analogCh);
228 } 224 }
229 } 225 }
230 } 226 }
231 // TODO: see if we can rewrite libpd_process_float so that it takes a buffer 227 libpd_process_sys(); // process the block
232 // of interleaved channels of arbitrary length rather than a series of
233 // stacked buffers of size gLibPdBlockSize as it currently does.
234 // This would allow to use the buffers as they are rather than having to copy them
235 libpd_process_float(1, &gInBuf[oldInW], &gOutBuf[oldInW]);
236 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved 228 for(unsigned int n = 0; n < gLibpdBlockSize; ++n){ //pd buffers are interleaved
237 unsigned int outAudioFrame = n + j * gLibpdBlockSize; 229 unsigned int outAudioFrame = 0;
238 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ 230 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){
239 audioWrite(context, outAudioFrame, ch, gOutBuf[outR++]); 231 audioWrite(context, outAudioFrame, ch, gOutBuf[outR++]);
240 } 232 }
241 //and analogs 233 //and analogs
242 if(context->analogChannels == 8){ 234 if(context->analogChannels == 8){
270 // Release any resources that were allocated in setup(). 262 // Release any resources that were allocated in setup().
271 263
272 void cleanup(BelaContext *context, void *userData) 264 void cleanup(BelaContext *context, void *userData)
273 { 265 {
274 libpd_queued_release(); 266 libpd_queued_release();
275 free(gInBuf); 267 // free(gInBuf);
276 free(gOutBuf); 268 // free(gOutBuf);
277 } 269 }