Mercurial > hg > beaglert
comparison examples/basic_libpd/render.cpp @ 300:dbeed520b014 prerelease
Renamed projects to examples
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Fri, 27 May 2016 13:58:20 +0100 |
parents | projects/basic_libpd/render.cpp@600355cf4ed5 |
children | e4392164b458 |
comparison
equal
deleted
inserted
replaced
297:a3d83ebdf49b | 300:dbeed520b014 |
---|---|
1 /* | |
2 * render.cpp | |
3 * | |
4 * Created on: Oct 24, 2014 | |
5 * Author: parallels | |
6 */ | |
7 | |
8 #include <BeagleRT.h> | |
9 #include <cmath> | |
10 #include <Utilities.h> | |
11 #include <I2c_Codec.h> | |
12 #include <PRU.h> | |
13 #include <stdio.h> | |
14 #include "z_libpd.h" | |
15 #include <UdpServer.h> | |
16 | |
17 // setup() is called once before the audio rendering starts. | |
18 // Use it to perform any initialisation and allocation which is dependent | |
19 // on the period size or sample rate. | |
20 // | |
21 // userData holds an opaque pointer to a data structure that was passed | |
22 // in from the call to initAudio(). | |
23 // | |
24 // Return true on success; returning false halts the program. | |
25 #define DEFDACBLKSIZE 8u //make sure this matches the one used to compile libpd | |
26 | |
27 int gChannelsInUse = 10; | |
28 int gBufLength; | |
29 | |
30 float* gInBuf; | |
31 float* gOutBuf; | |
32 | |
33 void pdnoteon(int ch, int pitch, int vel) { | |
34 printf("noteon: %d %d %d\n", ch, pitch, vel); | |
35 } | |
36 | |
37 void BeagleRT_printHook(const char *recv){ | |
38 rt_printf("%s", recv); | |
39 } | |
40 | |
41 UdpServer udpServer; | |
42 | |
43 void udpRead(){ | |
44 char dest[100] = {0}; | |
45 while(!gShouldStop){ | |
46 libpd_sys_microsleep(0); | |
47 usleep(1000); | |
48 } | |
49 } | |
50 | |
51 AuxiliaryTask udpReadTask; | |
52 bool setup(BeagleRTContext *context, void *userData) | |
53 { | |
54 gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse); | |
55 udpServer.bindToPort(1234); | |
56 | |
57 // check that we are not running with a blocksize smaller than DEFDACBLKSIZE | |
58 // it would still work, but the load would be executed unevenly between calls to render | |
59 if(context->audioFrames < DEFDACBLKSIZE){ | |
60 fprintf(stderr, "Error: minimum block size must be %d\n", DEFDACBLKSIZE); | |
61 return false; | |
62 } | |
63 | |
64 // check that the sampling rate of the analogs is the same as audio if running with | |
65 // more than 2 channels (that is with analog). If we fix the TODO in render, then | |
66 // this test is not needed. | |
67 // if(context->analogFrames != context->audioFrames){ | |
68 // fprintf(stderr, "Error: analog and audio sampling rates must be the same\n"); | |
69 // return false; | |
70 // } | |
71 //following lines borrowed from libpd/samples/c/pdtest/pdtest.c | |
72 // init pd | |
73 libpd_set_printhook(BeagleRT_printHook); // set this before calling libpd_init | |
74 libpd_set_noteonhook(pdnoteon); | |
75 libpd_init(); | |
76 //TODO: analyse the ASCII of the patch file and find the in/outs to use | |
77 libpd_init_audio(gChannelsInUse, gChannelsInUse, context->audioSampleRate); | |
78 | |
79 libpd_start_message(1); // one entry in list | |
80 libpd_add_float(1.0f); | |
81 libpd_finish_message("pd", "dsp"); | |
82 | |
83 gBufLength = max(DEFDACBLKSIZE, context->audioFrames); | |
84 unsigned int bufferSize = sizeof(float)*gChannelsInUse*gBufLength; | |
85 gInBuf = (float*)malloc(bufferSize); | |
86 gOutBuf = (float*)malloc(bufferSize); | |
87 // no need to memset to zero | |
88 | |
89 char file[] = "_main.pd"; | |
90 char folder[] = "./"; | |
91 // open patch [; pd open file folder( | |
92 libpd_openfile(file, folder); | |
93 | |
94 udpReadTask = BeagleRT_createAuxiliaryTask(udpRead, 60, "udpReadTask"); | |
95 BeagleRT_scheduleAuxiliaryTask(udpReadTask); | |
96 return true; | |
97 } | |
98 | |
99 // render() is called regularly at the highest priority by the audio engine. | |
100 // Input and output are given from the audio hardware and the other | |
101 // ADCs and DACs (if available). If only audio is available, numMatrixFrames | |
102 // will be 0. | |
103 BeagleRTContext *c; | |
104 void render(BeagleRTContext *context, void *userData) | |
105 { | |
106 static int inW = 0; | |
107 static int outR = 0; | |
108 /* | |
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 | |
111 * do not need the for loops before and after libpd_process_float, so you can save quite some | |
112 * memory operations. | |
113 */ | |
114 static int analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels); | |
115 // rt_printf("channelsInUse: %d, analogChannels in Use: %d\n", gChannelsInUse, analogChannelsInUse); | |
116 for(unsigned int n = 0; n < context->audioFrames; ++n){ //pd buffers are interleaved | |
117 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ //first two channels are audio | |
118 gInBuf[inW++] = audioReadFrame(context, n, ch); | |
119 } | |
120 // then analogs | |
121 // this loop resamples by ZOH, as needed, using m | |
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 } | |
134 } | |
135 if(inW == gBufLength * gChannelsInUse){ | |
136 inW = 0; | |
137 } | |
138 } | |
139 // rt_printf("inW %d\n", inW); | |
140 if(inW == 0){ //if the buffer is full, process it | |
141 static int numberOfPdBlocksToProcess = gBufLength/DEFDACBLKSIZE; | |
142 libpd_process_float(numberOfPdBlocksToProcess, gInBuf, gOutBuf); | |
143 outR = 0; // reset the read pointer. NOTE: hopefully this is needed only the first time | |
144 } | |
145 | |
146 for(unsigned int n = 0; n < context->audioFrames; n++){ //pd buffers are interleaved | |
147 for(unsigned int ch = 0; ch < context->audioChannels; ++ch){ | |
148 audioWriteFrame(context, n, ch, gOutBuf[outR++]); | |
149 } | |
150 //and analogs | |
151 if(context->analogChannels == 8){ | |
152 for(unsigned int analogCh = 0; analogCh < analogChannelsInUse; ++analogCh){ | |
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 } | |
171 } | |
172 if(outR == gBufLength * gChannelsInUse){ | |
173 outR = 0; | |
174 } | |
175 } | |
176 // rt_printf("outR %d, analogChannelsInUse %d, channelsInUse %d\n", | |
177 // outR , analogChannelsInUse, gChannelsInUse); | |
178 } | |
179 | |
180 // cleanup() is called once at the end, after the audio has stopped. | |
181 // Release any resources that were allocated in setup(). | |
182 | |
183 void cleanup(BeagleRTContext *context, void *userData) | |
184 { | |
185 free(gInBuf); | |
186 free(gOutBuf); | |
187 } |