comparison projects/basic_libpd/render.cpp @ 232:600355cf4ed5 mergingClockSync

libpd taking care of different numbers of analog channels
author Giulio Moro <giuliomoro@yahoo.it>
date Sun, 10 Apr 2016 03:14:33 +0200
parents af211ee57867
children
comparison
equal deleted inserted replaced
231:c0bf6157f67e 232:600355cf4ed5
22 // in from the call to initAudio(). 22 // in from the call to initAudio().
23 // 23 //
24 // Return true on success; returning false halts the program. 24 // Return true on success; returning false halts the program.
25 #define DEFDACBLKSIZE 8u //make sure this matches the one used to compile libpd 25 #define DEFDACBLKSIZE 8u //make sure this matches the one used to compile libpd
26 26
27 const int gChannelsInUse = 6; 27 int gChannelsInUse = 10;
28 int gBufLength; 28 int gBufLength;
29 29
30 float* gInBuf; 30 float* gInBuf;
31 float* gOutBuf; 31 float* gOutBuf;
32 32
49 } 49 }
50 50
51 AuxiliaryTask udpReadTask; 51 AuxiliaryTask udpReadTask;
52 bool setup(BeagleRTContext *context, void *userData) 52 bool setup(BeagleRTContext *context, void *userData)
53 { 53 {
54 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse);
54 udpServer.bindToPort(1234); 55 udpServer.bindToPort(1234);
55 56
56 // check that we are not running with a blocksize smaller than DEFDACBLKSIZE 57 // check that we are not running with a blocksize smaller than DEFDACBLKSIZE
57 // it would still work, but the load would be executed unevenly between calls to render 58 // it would still work, but the load would be executed unevenly between calls to render
58 if(context->audioFrames < DEFDACBLKSIZE){ 59 if(context->audioFrames < DEFDACBLKSIZE){
61 } 62 }
62 63
63 // check that the sampling rate of the analogs is the same as audio if running with 64 // check that the sampling rate of the analogs is the same as audio if running with
64 // more than 2 channels (that is with analog). If we fix the TODO in render, then 65 // more than 2 channels (that is with analog). If we fix the TODO in render, then
65 // this test is not needed. 66 // this test is not needed.
66 if(context->analogFrames != context->audioFrames){ 67 // if(context->analogFrames != context->audioFrames){
67 fprintf(stderr, "Error: analog and audio sampling rates must be the same\n"); 68 // fprintf(stderr, "Error: analog and audio sampling rates must be the same\n");
68 return false; 69 // return false;
69 } 70 // }
70 //following lines borrowed from libpd/samples/c/pdtest/pdtest.c 71 //following lines borrowed from libpd/samples/c/pdtest/pdtest.c
71 // init pd 72 // init pd
72 libpd_set_printhook(BeagleRT_printHook); // set this before calling libpd_init 73 libpd_set_printhook(BeagleRT_printHook); // set this before calling libpd_init
73 libpd_set_noteonhook(pdnoteon); 74 libpd_set_noteonhook(pdnoteon);
74 libpd_init(); 75 libpd_init();
82 gBufLength = max(DEFDACBLKSIZE, context->audioFrames); 83 gBufLength = max(DEFDACBLKSIZE, context->audioFrames);
83 unsigned int bufferSize = sizeof(float)*gChannelsInUse*gBufLength; 84 unsigned int bufferSize = sizeof(float)*gChannelsInUse*gBufLength;
84 gInBuf = (float*)malloc(bufferSize); 85 gInBuf = (float*)malloc(bufferSize);
85 gOutBuf = (float*)malloc(bufferSize); 86 gOutBuf = (float*)malloc(bufferSize);
86 // no need to memset to zero 87 // no need to memset to zero
87
88 88
89 char file[] = "_main.pd"; 89 char file[] = "_main.pd";
90 char folder[] = "./"; 90 char folder[] = "./";
91 // open patch [; pd open file folder( 91 // open patch [; pd open file folder(
92 libpd_openfile(file, folder); 92 libpd_openfile(file, folder);
109 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers 109 * NOTE: if you are only using audio (or only analogs) and you are using interleaved buffers
110 * and the blocksize of Bela is the same as DEFDACBLKSIZE, then you probably 110 * and the blocksize of Bela is the same as DEFDACBLKSIZE, then you probably
111 * do not need the for loops before and after libpd_process_float, so you can save quite some 111 * do not need the for loops before and after libpd_process_float, so you can save quite some
112 * memory operations. 112 * memory operations.
113 */ 113 */
114 114 static int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels);
115 for(unsigned int n = 0; n < context->audioFrames; n++){ //pd buffers are interleaved 115 // rt_printf("channelsInUse: %d, analogChannels in Use: %d\n", gChannelsInUse, analogChannelsInUse);
116 for(unsigned int k = 0; k < context->audioChannels; k++){ 116 for(unsigned int n = 0; n < context->audioFrames; ++n){ //pd buffers are interleaved
117 gInBuf[inW++] = audioReadFrame(context, n, k); 117 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ //first two channels are audio
118 gInBuf[inW++] = audioReadFrame(context, n, ch);
118 } 119 }
119 for(unsigned int k = 0; k < gChannelsInUse - context->audioChannels; k ++){ // add analogs 120 // then analogs
120 gInBuf[inW++] = analogReadFrame(context, n, k); 121 // this loop resamples by ZOH, as needed, using m
121 // TODO: Apply here sampling rate conversion from analogs to audio 122 if(context->analogChannels == 8 ){ //hold the value for two frames
123 for(int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
124 gInBuf[inW++] = analogReadFrame(context, n/2, analogCh); // n/2 wil be the same for n and n+1 when n is even
125 }
126 } else if(context->analogChannels == 4){ //write every frame
127 for(int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
128 gInBuf[inW++] = analogReadFrame(context, n, analogCh);
129 }
130 } else if(context->analogChannels == 2){ //drop every other frame
131 for(int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
132 gInBuf[inW++] = analogReadFrame(context, n*2, analogCh);
133 }
122 } 134 }
123 if(inW == gBufLength * gChannelsInUse){ 135 if(inW == gBufLength * gChannelsInUse){
124 inW = 0; 136 inW = 0;
125 } 137 }
126 } 138 }
127 139 // rt_printf("inW %d\n", inW);
128 if(inW == 0){ //if the buffer is full, process it 140 if(inW == 0){ //if the buffer is full, process it
129 int numberOfPdBlocksToProcess = gBufLength/DEFDACBLKSIZE; 141 static int numberOfPdBlocksToProcess = gBufLength/DEFDACBLKSIZE;
130 libpd_process_float(numberOfPdBlocksToProcess, gInBuf, gOutBuf); 142 libpd_process_float(numberOfPdBlocksToProcess, gInBuf, gOutBuf);
131 outR = 0; // reset the read pointer. NOTE: hopefully this is not needed EXCEPT the first time 143 outR = 0; // reset the read pointer. NOTE: hopefully this is needed only the first time
132 } 144 }
133 145
134 for(unsigned int n = 0; n < context->audioFrames; n++){ //pd buffers are interleaved 146 for(unsigned int n = 0; n < context->audioFrames; n++){ //pd buffers are interleaved
135 for(unsigned int k = 0; k < context->audioChannels; k++){ 147 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){
136 audioWriteFrame(context, n, k, gOutBuf[outR++]); 148 audioWriteFrame(context, n, ch, gOutBuf[outR++]);
137 } 149 }
138 //add analogs here, limit them to channelsInUse 150 //and analogs
139 for(unsigned int k = 0; k < gChannelsInUse - context->audioChannels; k ++){ // add analogs 151 if(context->analogChannels == 8){
140 analogWriteFrame(context, n, k, gOutBuf[outR++]); 152 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
141 // TODO: Apply here sampling rate conversion from analogs to audio 153 float analogOut = gOutBuf[outR++];
154 if((n&1) == 0){//write every two frames
155 analogWriteFrame(context, n/2, analogCh, analogOut);
156 } else {
157 // discard this sample
158 }
159 }
160 } else if(context->analogChannels == 4){ //write every frame
161 for(int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
162 float analogOut = gOutBuf[outR++];
163 analogWriteFrame(context, n, analogCh, analogOut);
164 }
165 } else if(context->analogChannels == 2){ //write twice every frame
166 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){
167 float analogOut = gOutBuf[outR++];
168 analogWriteFrame(context, 2*n, analogCh, analogOut);
169 analogWriteFrame(context, 2*n + 1, analogCh, analogOut);
170 }
142 } 171 }
143 if(outR == gBufLength * gChannelsInUse){ 172 if(outR == gBufLength * gChannelsInUse){
144 outR = 0; 173 outR = 0;
145 } 174 }
146 } 175 }
176 // rt_printf("outR %d, analogChannelsInUse %d, channelsInUse %d\n",
177 // outR , analogChannelsInUse, gChannelsInUse);
147 } 178 }
179
148 // cleanup() is called once at the end, after the audio has stopped. 180 // cleanup() is called once at the end, after the audio has stopped.
149 // Release any resources that were allocated in setup(). 181 // Release any resources that were allocated in setup().
150 182
151 void cleanup(BeagleRTContext *context, void *userData) 183 void cleanup(BeagleRTContext *context, void *userData)
152 { 184 {