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 }