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 */