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