chris@160
|
1 /*
|
chris@160
|
2 * render.cpp
|
chris@160
|
3 *
|
chris@160
|
4 * Template render.cpp file for on-board heavy compiling
|
chris@160
|
5 *
|
chris@160
|
6 * N.B. this is currently *not* compatible with foleyDesigner source files!
|
chris@160
|
7 *
|
chris@160
|
8 * Created on: November 5, 2015
|
chris@160
|
9 *
|
chris@160
|
10 * Christian Heinrichs
|
chris@160
|
11 *
|
chris@160
|
12 */
|
chris@160
|
13
|
giuliomoro@329
|
14 #include <Bela.h>
|
giuliomoro@198
|
15 #include <Midi.h>
|
chris@160
|
16 #include <cmath>
|
chris@160
|
17 #include "Heavy_bbb.h"
|
chris@190
|
18 #include <string.h>
|
chris@190
|
19 #include <stdlib.h>
|
chris@190
|
20 #include <string.h>
|
chris@160
|
21 /*
|
chris@160
|
22 * HEAVY CONTEXT & BUFFERS
|
chris@160
|
23 */
|
chris@160
|
24
|
chris@160
|
25 Hv_bbb *gHeavyContext;
|
chris@160
|
26 float *gHvInputBuffers = NULL, *gHvOutputBuffers = NULL;
|
chris@160
|
27 int gHvInputChannels = 0, gHvOutputChannels = 0;
|
chris@160
|
28
|
chris@160
|
29 float gInverseSampleRate;
|
chris@160
|
30
|
chris@160
|
31 /*
|
chris@160
|
32 * HEAVY FUNCTIONS
|
chris@160
|
33 */
|
chris@160
|
34
|
chris@160
|
35 void printHook(double timestampSecs, const char *printLabel, const char *msgString, void *userData) {
|
chris@160
|
36 printf("Message from Heavy patch: [@ %.3f] %s: %s\n", timestampSecs, printLabel, msgString);
|
chris@160
|
37 }
|
chris@160
|
38
|
chris@160
|
39 static void sendHook(
|
chris@160
|
40 double timestamp, // in milliseconds
|
chris@160
|
41 const char *receiverName,
|
chris@160
|
42 const HvMessage *const m,
|
chris@160
|
43 void *userData) {
|
chris@160
|
44
|
chris@160
|
45 // only react to messages sent to receivers named "hello"
|
chris@160
|
46 if (!strncmp(receiverName, "hello", 5)) {
|
chris@160
|
47 }
|
chris@160
|
48
|
chris@160
|
49 }
|
chris@160
|
50
|
chris@160
|
51 /*
|
chris@166
|
52 * SETUP, RENDER LOOP & CLEANUP
|
chris@160
|
53 */
|
chris@160
|
54
|
giuliomoro@198
|
55 Midi midi;
|
giuliomoro@329
|
56 bool setup(BelaContext *context, void *userData) {
|
chris@160
|
57
|
chris@160
|
58 /* HEAVY */
|
chris@160
|
59
|
chris@160
|
60 gHeavyContext = hv_bbb_new(context->audioSampleRate);
|
chris@160
|
61
|
chris@160
|
62 gHvInputChannels = hv_getNumInputChannels(gHeavyContext);
|
chris@160
|
63 gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext);
|
chris@160
|
64
|
chris@160
|
65 rt_printf("Starting Heavy context with %d input channels and %d output channels\n",
|
chris@160
|
66 gHvInputChannels, gHvOutputChannels);
|
chris@160
|
67
|
chris@160
|
68 if(gHvInputChannels != 0) {
|
chris@160
|
69 gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float));
|
chris@160
|
70 }
|
chris@160
|
71 if(gHvOutputChannels != 0) {
|
chris@160
|
72 gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float));
|
chris@160
|
73 }
|
chris@160
|
74
|
chris@160
|
75 gInverseSampleRate = 1.0 / context->audioSampleRate;
|
chris@160
|
76
|
chris@160
|
77 // Set heavy print hook
|
chris@160
|
78 hv_setPrintHook(gHeavyContext, &printHook);
|
chris@160
|
79 // Set heavy send hook
|
chris@160
|
80 hv_setSendHook(gHeavyContext, sendHook);
|
chris@160
|
81
|
giuliomoro@198
|
82 midi.readFrom(0);
|
giuliomoro@198
|
83 midi.writeTo(0);
|
giuliomoro@198
|
84 midi.enableParser(true);
|
chris@160
|
85 return true;
|
chris@160
|
86 }
|
chris@160
|
87
|
chris@160
|
88
|
giuliomoro@329
|
89 void render(BelaContext *context, void *userData)
|
chris@160
|
90 {
|
chris@160
|
91
|
chris@160
|
92 // De-interleave the data
|
chris@160
|
93 if(gHvInputBuffers != NULL) {
|
chris@160
|
94 for(int n = 0; n < context->audioFrames; n++) {
|
chris@160
|
95 for(int ch = 0; ch < gHvInputChannels; ch++) {
|
chris@160
|
96 if(ch >= context->audioChannels+context->analogChannels) {
|
chris@160
|
97 // THESE ARE PARAMETER INPUT 'CHANNELS' USED FOR ROUTING
|
chris@160
|
98 // 'sensor' outputs from routing channels of dac~ are passed through here
|
chris@160
|
99 break;
|
chris@160
|
100 } else {
|
chris@160
|
101 // If more than 2 ADC inputs are used in the pd patch, route the analog inputs
|
chris@160
|
102 // i.e. ADC3->analogIn0 etc. (first two are always audio inputs)
|
chris@160
|
103 if(ch >= context->audioChannels) {
|
chris@160
|
104 int m = n/2;
|
chris@160
|
105 float mIn = context->analogIn[m*context->analogChannels + (ch-context->audioChannels)];
|
chris@160
|
106 gHvInputBuffers[ch * context->audioFrames + n] = mIn;
|
chris@160
|
107 } else {
|
chris@160
|
108 gHvInputBuffers[ch * context->audioFrames + n] = context->audioIn[n * context->audioChannels + ch];
|
chris@160
|
109 }
|
chris@160
|
110 }
|
chris@160
|
111 }
|
chris@160
|
112 }
|
chris@160
|
113 }
|
chris@160
|
114
|
chris@160
|
115 // replacement for bang~ object
|
chris@160
|
116 //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b");
|
giuliomoro@198
|
117 {
|
giuliomoro@198
|
118 int num;
|
giuliomoro@289
|
119 unsigned int hvHashes[3];
|
giuliomoro@289
|
120 hvHashes[0] = hv_stringToHash("bela_notein");
|
giuliomoro@289
|
121 hvHashes[1] = hv_stringToHash("bela_ctlin");
|
giuliomoro@289
|
122 hvHashes[2] = hv_stringToHash("bela_pgmin");
|
giuliomoro@198
|
123 while((num = midi.getParser()->numAvailableMessages()) > 0){
|
giuliomoro@198
|
124 static MidiChannelMessage message;
|
giuliomoro@198
|
125 message = midi.getParser()->getNextChannelMessage();
|
giuliomoro@198
|
126 switch(message.getType()){
|
giuliomoro@198
|
127 case kmmNoteOn: {
|
giuliomoro@198
|
128 // message.prettyPrint();
|
giuliomoro@198
|
129 float noteNumber = message.getDataByte(0);
|
giuliomoro@198
|
130 float velocity = message.getDataByte(1);
|
giuliomoro@198
|
131 float channel = message.getChannel();
|
giuliomoro@198
|
132 // rt_printf("message: noteNumber: %f, velocity: %f, channel: %f\n", noteNumber, velocity, channel);
|
giuliomoro@289
|
133 hv_vscheduleMessageForReceiver(gHeavyContext, hvHashes[0], 0, "fff", noteNumber, velocity, channel);
|
giuliomoro@198
|
134 }
|
giuliomoro@198
|
135 break;
|
giuliomoro@198
|
136 case kmmControlChange: {
|
giuliomoro@289
|
137 hv_vscheduleMessageForReceiver(gHeavyContext, hvHashes[1], 0, "fff",
|
giuliomoro@198
|
138 (float)message.getDataByte(1), (float)message.getDataByte(0), (float)message.getChannel());
|
giuliomoro@198
|
139 }
|
giuliomoro@198
|
140 break;
|
giuliomoro@198
|
141 case kmmProgramChange:
|
giuliomoro@289
|
142 hv_vscheduleMessageForReceiver(gHeavyContext, hvHashes[2], 0, "ff",
|
giuliomoro@198
|
143 (float)message.getDataByte(0), (float)message.getChannel());
|
giuliomoro@198
|
144 break;
|
giuliomoro@198
|
145 }
|
giuliomoro@198
|
146 }
|
giuliomoro@198
|
147 }
|
giuliomoro@198
|
148 // hv_sendFloatToReceiver(gHeavyContext, "notein", 1.123f);
|
giuliomoro@198
|
149
|
chris@160
|
150
|
chris@160
|
151 hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames);
|
chris@160
|
152
|
chris@160
|
153 // Interleave the output data
|
chris@160
|
154 if(gHvOutputBuffers != NULL) {
|
chris@160
|
155 for(int n = 0; n < context->audioFrames; n++) {
|
chris@160
|
156
|
chris@160
|
157 for(int ch = 0; ch < gHvOutputChannels; ch++) {
|
chris@160
|
158 if(ch >= context->audioChannels+context->analogChannels) {
|
chris@160
|
159 // THESE ARE SENSOR OUTPUT 'CHANNELS' USED FOR ROUTING
|
chris@160
|
160 // they are the content of the 'sensor output' dac~ channels
|
chris@160
|
161 } else {
|
chris@160
|
162 if(ch >= context->audioChannels) {
|
chris@160
|
163 int m = n/2;
|
chris@160
|
164 context->analogOut[m * context->analogFrames + (ch-context->audioChannels)] = constrain(gHvOutputBuffers[ch*context->audioFrames + n],0.0,1.0);
|
chris@160
|
165 } else {
|
chris@160
|
166 context->audioOut[n * context->audioChannels + ch] = gHvOutputBuffers[ch * context->audioFrames + n];
|
chris@160
|
167 }
|
chris@160
|
168 }
|
chris@160
|
169 }
|
chris@160
|
170 }
|
chris@160
|
171 }
|
chris@160
|
172
|
chris@160
|
173 }
|
chris@160
|
174
|
chris@160
|
175
|
giuliomoro@329
|
176 void cleanup(BelaContext *context, void *userData)
|
chris@160
|
177 {
|
chris@160
|
178
|
chris@160
|
179 hv_bbb_free(gHeavyContext);
|
chris@160
|
180 if(gHvInputBuffers != NULL)
|
chris@160
|
181 free(gHvInputBuffers);
|
chris@160
|
182 if(gHvOutputBuffers != NULL)
|
chris@160
|
183 free(gHvOutputBuffers);
|
chris@160
|
184
|
chris@160
|
185 }
|