Mercurial > hg > beaglert
comparison projects/heavy/hello-world/HvMessage.c @ 160:5bcf04234f80 heavy-updated
- added -std=c99 to Makefile for user-supplied C files (required for heavy files)
- changed heavy core render.cpp file to use latest API and removed all redundant functions (e.g. foleyDesigner/touchkey stuff)
- use build_pd.sh to compile and run pd files (-h for usage instructions)
author | chnrx <chris.heinrichs@gmail.com> |
---|---|
date | Thu, 05 Nov 2015 18:58:26 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
159:1e7db6610600 | 160:5bcf04234f80 |
---|---|
1 /** | |
2 * Copyright (c) 2014, 2015, Enzien Audio Ltd. | |
3 * | |
4 * Permission to use, copy, modify, and/or distribute this software for any | |
5 * purpose with or without fee is hereby granted, provided that the above | |
6 * copyright notice and this permission notice appear in all copies. | |
7 * | |
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | |
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | |
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | |
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
14 * PERFORMANCE OF THIS SOFTWARE. | |
15 */ | |
16 | |
17 #include "HvMessage.h" | |
18 | |
19 HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) { | |
20 m->timestamp = timestamp; | |
21 m->numElements = (hv_uint16_t) numElements; | |
22 m->numBytes = (hv_uint16_t) msg_getByteSize(numElements); | |
23 return m; | |
24 } | |
25 | |
26 HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) { | |
27 m->timestamp = timestamp; | |
28 m->numElements = 1; | |
29 m->numBytes = sizeof(HvMessage); | |
30 msg_setFloat(m, 0, f); | |
31 return m; | |
32 } | |
33 | |
34 HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) { | |
35 m->timestamp = timestamp; | |
36 m->numElements = 1; | |
37 m->numBytes = sizeof(HvMessage); | |
38 msg_setBang(m, 0); | |
39 return m; | |
40 } | |
41 | |
42 HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, char *s) { | |
43 m->timestamp = timestamp; | |
44 m->numElements = 1; | |
45 m->numBytes = sizeof(HvMessage); | |
46 msg_setSymbol(m, 0, s); | |
47 return m; | |
48 } | |
49 | |
50 HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) { | |
51 m->timestamp = timestamp; | |
52 m->numElements = 1; | |
53 m->numBytes = sizeof(HvMessage); | |
54 msg_setHash(m, 0, h); | |
55 return m; | |
56 } | |
57 | |
58 HvMessage *msg_initV(HvMessage *const m, const hv_uint32_t timestamp, const char *format, ...) { | |
59 va_list ap; | |
60 va_start(ap, format); | |
61 | |
62 const int numElem = (int) hv_strlen(format); | |
63 msg_init(m, numElem, timestamp); | |
64 for (int i = 0; i < numElem; i++) { | |
65 switch (format[i]) { | |
66 case 'b': msg_setBang(m,i); break; | |
67 case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; | |
68 case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; | |
69 case 'h': // hash not supported | |
70 default: break; | |
71 } | |
72 } | |
73 va_end(ap); | |
74 | |
75 return m; | |
76 } | |
77 | |
78 hv_size_t msg_getNumHeapBytes(const HvMessage *m) { | |
79 // get the size of all symbol elements | |
80 hv_size_t rsizeofsym = 0; | |
81 for (int i = 0; i < msg_getNumElements(m); ++i) { | |
82 if (msg_isSymbol(m,i)) { | |
83 rsizeofsym += (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // +1 to allow for trailing '\0' | |
84 } | |
85 } | |
86 | |
87 // the total byte size on the heap | |
88 return (msg_getByteSize(msg_getNumElements(m)) + rsizeofsym); | |
89 } | |
90 | |
91 void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) { | |
92 HvMessage *r = (HvMessage *) buffer; | |
93 | |
94 // assert that the message is not already larger than the length of the buffer | |
95 hv_assert(msg_getNumBytes(m) <= len); | |
96 | |
97 // copy the basic message to the buffer | |
98 hv_memcpy(r, m, msg_getNumBytes(m)); | |
99 | |
100 hv_size_t len_r = msg_getNumBytes(m); | |
101 | |
102 char *p = buffer + msg_getByteSize(msg_getNumElements(m)); // points to the end of the base message | |
103 for (int i = 0; i < msg_getNumElements(m); ++i) { | |
104 if (msg_isSymbol(m,i)) { | |
105 const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char | |
106 hv_assert(len_r + symLen <= len); // stay safe! | |
107 hv_strncpy(p, msg_getSymbol(m,i), symLen); | |
108 msg_setSymbol(r, i, p); | |
109 p += symLen; | |
110 len_r += symLen; | |
111 } | |
112 } | |
113 | |
114 r->numBytes = (hv_uint16_t) len_r; // update the message size in memory | |
115 } | |
116 | |
117 // the message is serialised such that all symbol elements are placed in order at the end of the buffer | |
118 HvMessage *msg_copy(const HvMessage *m) { | |
119 const hv_size_t heapSize = msg_getNumHeapBytes(m); | |
120 char *r = (char *) hv_malloc(heapSize); | |
121 msg_copyToBuffer(m, r, heapSize); | |
122 return (HvMessage *) r; | |
123 } | |
124 | |
125 void msg_free(HvMessage *m) { | |
126 hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message | |
127 } | |
128 | |
129 bool msg_hasFormat(const HvMessage *m, const char *fmt) { | |
130 if (fmt == NULL) return false; | |
131 if (msg_getNumElements(m) != hv_strlen(fmt)) return false; | |
132 for (int i = 0; i < msg_getNumElements(m); i++) { | |
133 switch (fmt[i]) { | |
134 case 'b': if (!msg_isBang(m, i)) return false; break; | |
135 case 'f': if (!msg_isFloat(m, i)) return false; break; | |
136 case 's': if (!msg_isSymbol(m, i)) return false; break; | |
137 case 'h': if (!msg_isHash(m, i)) return false; break; | |
138 default: return false; | |
139 } | |
140 } | |
141 return true; | |
142 } | |
143 | |
144 bool msg_compareSymbol(const HvMessage *m, int i, const char *s) { | |
145 switch (msg_getType(m,i)) { | |
146 case SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s); | |
147 case HASH: return (msg_getHash(m,i) == msg_symbolToHash(s)); | |
148 default: return false; | |
149 } | |
150 } | |
151 | |
152 bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) { | |
153 if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) { | |
154 if (msg_getType(m, i_m) == msg_getType(n, i_n)) { | |
155 switch (msg_getType(m, i_m)) { | |
156 case BANG: return true; | |
157 case FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n)); | |
158 case SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n)); | |
159 case HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n); | |
160 default: break; | |
161 } | |
162 } | |
163 } | |
164 return false; | |
165 } | |
166 | |
167 void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) { | |
168 switch (msg_getType(m, i_m)) { | |
169 case BANG: msg_setBang(n, i_n); break; | |
170 case FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break; | |
171 case SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break; | |
172 case HASH: msg_setHash(n, i_n, msg_getHash(m, i_m)); | |
173 default: break; | |
174 } | |
175 } | |
176 | |
177 hv_uint32_t msg_symbolToHash(const char *s) { | |
178 // this hash is based MurmurHash2 | |
179 // http://en.wikipedia.org/wiki/MurmurHash | |
180 // https://sites.google.com/site/murmurhash/ | |
181 static const unsigned int n = 0x5bd1e995; | |
182 static const int r = 24; | |
183 | |
184 int len = (int) hv_strlen(s); | |
185 hv_uint32_t x = (hv_uint32_t) (len); // seed (0) ^ len | |
186 | |
187 while (len >= 4) { | |
188 hv_uint32_t k = *((hv_uint32_t *)s); | |
189 k *= n; | |
190 k ^= k >> r; | |
191 k *= n; | |
192 x *= n; | |
193 x ^= k; | |
194 s += 4; len -= 4; | |
195 } | |
196 | |
197 switch(len) { | |
198 case 3: x ^= s[2] << 16; | |
199 case 2: x ^= s[1] << 8; | |
200 case 1: x ^= s[0]; x *= n; | |
201 default: break; | |
202 } | |
203 | |
204 x ^= x >> 13; | |
205 x *= n; | |
206 x ^= x >> 15; | |
207 | |
208 return x; | |
209 } | |
210 | |
211 hv_uint32_t msg_getHash(const HvMessage *const m, int i) { | |
212 hv_assert(i < msg_getNumElements(m)); // invalid index | |
213 switch (msg_getType(m,i)) { | |
214 case BANG: return 0xFFFFFFFF; | |
215 case FLOAT: { | |
216 float f = msg_getFloat(m,i); | |
217 return *((hv_uint32_t *) &f); | |
218 } | |
219 case SYMBOL: return msg_symbolToHash(msg_getSymbol(m,i)); | |
220 case HASH: return (&(m->elem)+i)->data.h; | |
221 default: return 0; | |
222 } | |
223 } | |
224 | |
225 char *msg_toString(const HvMessage *m) { | |
226 hv_assert(msg_getNumElements(m) > 0); | |
227 int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int)); | |
228 int size = 0; // the total length of our final buffer | |
229 | |
230 // loop through every element in our list of atoms | |
231 // first loop figures out how long our buffer should be | |
232 for (int i = 0; i < msg_getNumElements(m); i++) { | |
233 // length of our string is each atom plus a space, or \0 on the end | |
234 switch (msg_getType(m, i)) { | |
235 case BANG: len[i] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break; | |
236 case FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break; | |
237 case SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break; | |
238 case HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; break; | |
239 default: break; | |
240 } | |
241 size += len[i]; | |
242 } | |
243 | |
244 hv_assert(size > 0); | |
245 | |
246 // now we do the piecewise concatenation into our final string | |
247 // the final buffer we will pass back after concatenating all strings - user should free it | |
248 char *finalString = (char *) hv_malloc(size*sizeof(char)); | |
249 int pos = 0; | |
250 for (int i = 0; i < msg_getNumElements(m); i++) { | |
251 // put a string representation of each atom into the final string | |
252 switch (msg_getType(m, i)) { | |
253 case BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break; | |
254 case FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break; | |
255 case SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break; | |
256 case HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break; | |
257 default: break; | |
258 } | |
259 pos += len[i]; | |
260 finalString[pos-1] = 32; // ASCII space | |
261 } | |
262 finalString[size-1] = '\0'; // ensure that the string is null terminated | |
263 return finalString; | |
264 } | |
265 | |
266 /* | |
267 * TODO(mhroth): unnecessary for now | |
268 bool msg_resolveDollarArguments(HvMessage *m, HvMessage *n, int z, char *buf, hv_size_t len, const char *args, ...) { | |
269 va_list ap; | |
270 va_start(ap, args); | |
271 | |
272 hv_memset(buf, 0, len); // clear the buffer | |
273 hv_size_t j = 0; // position in buffer | |
274 const hv_size_t numArgs = hv_strlen(args); // the number of arguments | |
275 | |
276 // if there is only one argument then the result has the chance of being a number, otherwise no | |
277 bool isNumber = (numArgs == 1); | |
278 | |
279 for (hv_size_t i = 0; i < numArgs; ++i) { | |
280 switch (args[i]) { | |
281 case 'i': { // a message index | |
282 const int index = (int) va_arg(ap, int); | |
283 if (index < 0) { | |
284 // $0 always resolve to "0" | |
285 const hv_size_t x = 1; | |
286 if (x < len-j) { // always < in order to allow for trailing \0 | |
287 j += snprintf(buf+j, len-j, "0"); | |
288 } | |
289 } else { | |
290 switch (msg_getType(m, index)) { | |
291 default: | |
292 case BANG: break; // this case should never happen | |
293 case FLOAT: { | |
294 const hv_size_t x = snprintf(NULL, 0, "%g", msg_getFloat(m,index)); | |
295 if (x < len-j) { // ensure that the buffer is big enough | |
296 j += snprintf(buf+j, len-j, "%g", msg_getFloat(m,index)); | |
297 } | |
298 break; | |
299 } | |
300 case SYMBOL: { | |
301 const hv_size_t x = snprintf(NULL, 0, "%s", msg_getSymbol(m,index)); | |
302 if (x < len-j) { | |
303 j += snprintf(buf+j, len-j, "%s", msg_getSymbol(m,index)); | |
304 isNumber = false; | |
305 } | |
306 break; | |
307 } | |
308 } | |
309 } | |
310 break; | |
311 } | |
312 case 's': { // a string | |
313 const char *s = (char *) va_arg(ap, char *); | |
314 const hv_size_t x = snprintf(NULL, 0, "%s", s); | |
315 if (x <= len-j) { | |
316 j += snprintf(buf+j, len-j, "%s", s); | |
317 isNumber = false; | |
318 } | |
319 break; | |
320 } | |
321 default: break; | |
322 } | |
323 } | |
324 | |
325 if (isNumber) { | |
326 msg_setFloat(n,z,(float) atof(buf)); | |
327 } else { | |
328 msg_setSymbol(n,z,buf); | |
329 } | |
330 | |
331 va_end(ap); | |
332 | |
333 return !isNumber; | |
334 } | |
335 */ |