comparison examples/basic_libpd/render.cpp @ 340:69d86429a1cf prerelease

More on libpd support for threads
author Giulio Moro <giuliomoro@yahoo.it>
date Mon, 06 Jun 2016 02:37:30 +0100
parents 1802f99cd77f
children 7af9c5be3434
comparison
equal deleted inserted replaced
339:02e6f96466f8 340:69d86429a1cf
23 // 23 //
24 // userData holds an opaque pointer to a data structure that was passed 24 // userData holds an opaque pointer to a data structure that was passed
25 // in from the call to initAudio(). 25 // in from the call to initAudio().
26 // 26 //
27 // Return true on success; returning false halts the program. 27 // Return true on success; returning false halts the program.
28 unsigned int gLibPdBlockSize; //make sure this matches the one used to compile libpd 28 unsigned int gLibpdBlockSize; //make sure this matches the one used to compile libpd
29 29
30 unsigned int gChannelsInUse = 10; 30 unsigned int gChannelsInUse = 10;
31 int gBufLength; 31 int gBufLength;
32 32
33 float* gInBuf; 33 float* gInBuf;
41 rt_printf("%s", recv); 41 rt_printf("%s", recv);
42 } 42 }
43 43
44 UdpServer udpServer; 44 UdpServer udpServer;
45 45
46 void udpRead(){ 46 void libpdReadFilesLoop(){
47 while(!gShouldStop){ 47 while(!gShouldStop){
48 // check for modified sockets/file descriptors 48 // check for modified sockets/file descriptors
49 // (libpd would normally do this every block WITHIN the audio thread) 49 // (libpd would normally do this every block WITHIN the audio thread)
50 // not sure if this is thread-safe at the moment 50 // not sure if this is thread-safe at the moment
51 libpd_sys_microsleep(0); 51 libpd_sys_microsleep(0);
52 usleep(1000); 52 usleep(1000);
53 } 53 }
54 } 54 }
55
55 #define PARSE_MIDI 56 #define PARSE_MIDI
56 AuxiliaryTask udpReadTask; 57 AuxiliaryTask libpdReadFilesTask;
58 AuxiliaryTask libpdProcessMessageQueueTask;
59 AuxiliaryTask libpdProcessMidiQueueTask;
57 Midi midi; 60 Midi midi;
58 61
59 bool setup(BelaContext *context, void *userData) 62 bool setup(BelaContext *context, void *userData)
60 { 63 {
61 midi.readFrom(0); 64 midi.readFrom(0);
66 midi.enableParser(false); 69 midi.enableParser(false);
67 #endif /* PARSE_MIDI */ 70 #endif /* PARSE_MIDI */
68 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse); 71 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse);
69 udpServer.bindToPort(1234); 72 udpServer.bindToPort(1234);
70 73
71 gLibPdBlockSize = libpd_blocksize(); 74 gLibpdBlockSize = libpd_blocksize();
72 // 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
73 // 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
74 if(context->audioFrames < gLibPdBlockSize){ 77 if(context->audioFrames < gLibpdBlockSize){
75 fprintf(stderr, "Error: minimum block size must be %d\n", gLibPdBlockSize); 78 fprintf(stderr, "Error: minimum block size must be %d\n", gLibpdBlockSize);
76 return false; 79 return false;
77 } 80 }
78 // init pd 81 // init pd
79 libpd_set_queued_printhook(Bela_printHook); // set this before calling libpd_init 82 libpd_set_queued_printhook(Bela_printHook); // set this before calling libpd_init
80 libpd_set_queued_noteonhook(pdnoteon); 83 libpd_set_queued_noteonhook(pdnoteon);
84 //TODO: add hooks for other midi events and generate MIDI output appropriately
81 libpd_queued_init(); 85 libpd_queued_init();
82 //TODO: analyse the ASCII of the patch file and find the in/outs to use 86 //TODO: ideally, we would analyse the ASCII of the patch file and find the in/outs to use
83 libpd_init_audio(gChannelsInUse, gChannelsInUse, context->audioSampleRate); 87 libpd_init_audio(gChannelsInUse, gChannelsInUse, context->audioSampleRate);
84 88
85 libpd_start_message(1); // one entry in list 89 libpd_start_message(1); // one entry in list
86 libpd_add_float(1.0f); 90 libpd_add_float(1.0f);
87 libpd_finish_message("pd", "dsp"); 91 libpd_finish_message("pd", "dsp");
88 92
89 gBufLength = max((uint32_t)gLibPdBlockSize, context->audioFrames); 93 gBufLength = max(gLibpdBlockSize, context->audioFrames);
90 unsigned int bufferSize = sizeof(float)*gChannelsInUse*gBufLength; 94 unsigned int bufferSize = sizeof(float)*gChannelsInUse*gBufLength;
91 gInBuf = (float*)malloc(bufferSize); 95 gInBuf = (float*)malloc(bufferSize);
92 gOutBuf = (float*)malloc(bufferSize); 96 gOutBuf = (float*)malloc(bufferSize);
93 // no need to memset to zero 97 // no need to memset to zero
94 98
95 char file[] = "_main.pd"; 99 char file[] = "_main.pd";
96 char folder[] = "./"; 100 char folder[] = "./";
97 // open patch [; pd open file folder( 101 // open patch [; pd open file folder(
98 libpd_openfile(file, folder); 102 libpd_openfile(file, folder);
99 103
100 udpReadTask = Bela_createAuxiliaryTask(udpRead, 60, "udpReadTask"); 104 libpdReadFilesTask = Bela_createAuxiliaryTask(libpdReadFilesLoop, 60, "libpdReadFiles");
101 Bela_scheduleAuxiliaryTask(udpReadTask); 105 Bela_scheduleAuxiliaryTask(libpdReadFilesTask);
106
107 // 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");
109 libpdProcessMessageQueueTask = Bela_createAuxiliaryTask(libpd_queued_receive_pd_messages, 70, "libpdProcessMessageQueue");
102 return true; 110 return true;
103 } 111 }
104 112
105 // render() is called regularly at the highest priority by the audio engine. 113 // render() is called regularly at the highest priority by the audio engine.
106 // Input and output are given from the audio hardware and the other 114 // Input and output are given from the audio hardware and the other
180 } 188 }
181 #else 189 #else
182 int input; 190 int input;
183 while((input = midi.getInput()) >= 0){ 191 while((input = midi.getInput()) >= 0){
184 libpd_midibyte(0, input); 192 libpd_midibyte(0, input);
185 rt_printf("input: %d\n", input);
186 } 193 }
187 #endif /* PARSE_MIDI */ 194 #endif /* PARSE_MIDI */
195
188 static unsigned int inW = 0; 196 static unsigned int inW = 0;
189 static unsigned int outR = 0; 197 static unsigned int outR = 0;
190 /* 198 /*
191 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers 199 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers
192 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably 200 * and the blocksize of Bela is the same as gLibPdBlockSize, then you probably
218 inW = 0; 226 inW = 0;
219 } 227 }
220 } 228 }
221 // rt_printf("inW %d\n", inW); 229 // rt_printf("inW %d\n", inW);
222 if(inW == 0){ //if the buffer is full, process it 230 if(inW == 0){ //if the buffer is full, process it
223 static int numberOfPdBlocksToProcess = gBufLength/gLibPdBlockSize; 231 static int numberOfPdBlocksToProcess = gBufLength/gLibpdBlockSize;
224 // TODO: see if we can rewrite libpd_process_float so that it takes a buffer 232 // TODO: see if we can rewrite libpd_process_float so that it takes a buffer
225 // of interleaved channels of arbitrary length channels rather than a series of 233 // of interleaved channels of arbitrary length rather than a series of
226 // stacked buffers of size gLibPdBlockSize as it currently does. 234 // stacked buffers of size gLibPdBlockSize as it currently does.
227 libpd_process_float(numberOfPdBlocksToProcess, gInBuf, gOutBuf); 235 libpd_process_float(numberOfPdBlocksToProcess, gInBuf, gOutBuf);
228 outR = 0; // reset the read pointer. NOTE: hopefully this is needed only the first time 236 outR = 0; // reset the read pointer. NOTE: hopefully this is needed only the first time
229 } 237 }
230 238
258 outR = 0; 266 outR = 0;
259 } 267 }
260 } 268 }
261 // rt_printf("outR %d, analogChannelsInUse %d, channelsInUse %d\n", 269 // rt_printf("outR %d, analogChannelsInUse %d, channelsInUse %d\n",
262 // outR , analogChannelsInUse, gChannelsInUse); 270 // outR , analogChannelsInUse, gChannelsInUse);
271 Bela_scheduleAuxiliaryTask(libpdProcessMidiQueueTask);
272 Bela_scheduleAuxiliaryTask(libpdProcessMessageQueueTask);
263 } 273 }
264 274
265 // cleanup() is called once at the end, after the audio has stopped. 275 // cleanup() is called once at the end, after the audio has stopped.
266 // Release any resources that were allocated in setup(). 276 // Release any resources that were allocated in setup().
267 277