Mercurial > hg > beaglert
changeset 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)
line wrap: on
line diff
--- a/Makefile Sun Oct 18 01:13:40 2015 +0100 +++ b/Makefile Thu Nov 05 18:58:26 2015 +0000 @@ -87,7 +87,7 @@ build/source/%.o: ./source/%.c @echo 'Building file: $<' @echo 'Invoking: GCC C Compiler' - gcc $(SYNTAX_FLAG) -I./include $(INCLUDES) -O2 -Wall -c -fmessage-length=0 -U_FORTIFY_SOURCE -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + gcc $(SYNTAX_FLAG) -I./include $(INCLUDES) -O2 -Wall -c -fmessage-length=0 -U_FORTIFY_SOURCE -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" -std=c99 @echo 'Finished building: $<' @echo ' '
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlBinop.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlBinop.h" + +hv_size_t cBinop_init(ControlBinop *o, float k) { + o->k = k; + return 0; +} + +static float cBinop_perform_op(BinopType op, float f, const float k) { + switch (op) { + case HV_BINOP_ADD: return f + k; + case HV_BINOP_SUBTRACT: return f - k; + case HV_BINOP_MULTIPLY: return f * k; + case HV_BINOP_DIVIDE: return (k != 0.0f) ? f / k : 0.0f; + case HV_BINOP_INT_DIV: return (float) ((int) f / (int) k); + case HV_BINOP_MOD_BIPOLAR: return (float) ((int) f % (int) k); + case HV_BINOP_MOD_UNIPOLAR: { + f = (k == 0.0f) ? 0.0f : (float) ((int) f % (int) k); + return (f < 0.0f) ? f + fabsf(k) : f; + } + case HV_BINOP_BIT_LEFTSHIFT: return (float) (((int) f) << ((int) k)); + case HV_BINOP_BIT_RIGHTSHIFT: return (float) (((int) f) >> ((int) k)); + case HV_BINOP_BIT_AND: return (float) ((int) f & (int) k); + case HV_BINOP_BIT_XOR: return (float) ((int) f ^ (int) k); + case HV_BINOP_BIT_OR: return (float) ((int) f | (int) k); + case HV_BINOP_EQ: return (f == k) ? 1.0f : 0.0f; + case HV_BINOP_NEQ: return (f != k) ? 1.0f : 0.0f; + case HV_BINOP_LOGICAL_AND: return ((f == 0.0f) || (k == 0.0f)) ? 0.0f : 1.0f; + case HV_BINOP_LOGICAL_OR: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : 1.0f; + case HV_BINOP_LESS_THAN: return (f < k) ? 1.0f : 0.0f; + case HV_BINOP_LESS_THAN_EQL: return (f <= k) ? 1.0f : 0.0f; + case HV_BINOP_GREATER_THAN: return (f > k) ? 1.0f : 0.0f; + case HV_BINOP_GREATER_THAN_EQL: return (f >= k) ? 1.0f : 0.0f; + case HV_BINOP_MAX: return hv_max_f(f, k); + case HV_BINOP_MIN: return hv_min_f(f, k); + case HV_BINOP_POW: return (f > 0.0f) ? powf(f, k) : 0.0f; + case HV_BINOP_ATAN2: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : atan2f(f, k); + default: return 0.0f; + } +} + +void cBinop_onMessage(HvBase *_c, ControlBinop *o, BinopType op, int letIn, + const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + switch (letIn) { + case 0: { + if (msg_isFloat(m, 0)) { + // Note(joe): supporting Pd's ability to perform operations of packs + // of floats is likely to not be supported in the future. + if (msg_isFloat(m, 1)) o->k = msg_getFloat(m, 1); + HvMessage *n = HV_MESSAGE_ON_STACK(1); + float f = cBinop_perform_op(op, msg_getFloat(m, 0), o->k); + msg_initWithFloat(n, msg_getTimestamp(m), f); + sendMessage(_c, 0, n); + } + break; + } + case 1: { + if (msg_isFloat(m, 0)) { + o->k = msg_getFloat(m, 0); + } + break; + } + default: break; + } +} + +void cBinop_k_onMessage(HvBase *_c, void *o, BinopType op, const float k, + int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + if (msg_isFloat(m, 0)) { + // NOTE(mhroth): Heavy does not support sending bangs to binop objects to return the previous output + float f = (msg_isFloat(m, 1)) ? msg_getFloat(m, 1) : k; + HvMessage *n = HV_MESSAGE_ON_STACK(1); + f = cBinop_perform_op(op, msg_getFloat(m, 0), f); + msg_initWithFloat(n, msg_getTimestamp(m), f); + sendMessage(_c, 0, n); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlBinop.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_BINOP_H_ +#define _HEAVY_CONTROL_BINOP_H_ + +#include "HvBase.h" + +typedef enum BinopType { + HV_BINOP_ADD, + HV_BINOP_SUBTRACT, + HV_BINOP_MULTIPLY, + HV_BINOP_DIVIDE, + HV_BINOP_INT_DIV, + HV_BINOP_MOD_BIPOLAR, + HV_BINOP_MOD_UNIPOLAR, + HV_BINOP_BIT_LEFTSHIFT, + HV_BINOP_BIT_RIGHTSHIFT, + HV_BINOP_BIT_AND, + HV_BINOP_BIT_XOR, + HV_BINOP_BIT_OR, + HV_BINOP_EQ, + HV_BINOP_NEQ, + HV_BINOP_LOGICAL_AND, + HV_BINOP_LOGICAL_OR, + HV_BINOP_LESS_THAN, + HV_BINOP_LESS_THAN_EQL, + HV_BINOP_GREATER_THAN, + HV_BINOP_GREATER_THAN_EQL, + HV_BINOP_MAX, + HV_BINOP_MIN, + HV_BINOP_POW, + HV_BINOP_ATAN2 +} BinopType; + +typedef struct ControlBinop { + float k; +} ControlBinop; + +hv_size_t cBinop_init(ControlBinop *o, float k); + +void cBinop_onMessage(HvBase *_c, ControlBinop *o, BinopType op, int letIn, + const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +void cBinop_k_onMessage(HvBase *_c, void *o, BinopType op, const float k, + int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +#endif // _HEAVY_CONTROL_BINOP_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlRandom.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlRandom.h" +#include "HvBase.h" + +// http://www.firstpr.com.au/dsp/rand31 +// http://en.wikipedia.org/wiki/Lehmer_random_number_generator + +hv_size_t cRandom_init(ControlRandom *o, int seed) { + o->state = (seed != 0) ? seed : 1; + return 0; +} + +void cRandom_onMessage(HvBase *_c, ControlRandom *o, int inletIndex, const HvMessage *m, + void (*sendMessage)(HvBase *, int, const HvMessage *)) { + switch (inletIndex) { + case 0: { + HvMessage *n = HV_MESSAGE_ON_STACK(1); + o->state = (int) ((((unsigned long long) o->state) * 279470273UL) % 4294967291UL); + float f = ((float) (o->state >> 9)) * 0.00000011920929f; + msg_initWithFloat(n, msg_getTimestamp(m), f); + sendMessage(_c, 0, n); + break; + } + case 1: { + if (msg_isFloat(m,0)) { + o->state = (int) msg_getFloat(m,0); + } + break; + } + default: break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlRandom.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_RANDOM_H_ +#define _HEAVY_CONTROL_RANDOM_H_ + +#include "HvBase.h" + +typedef struct ControlRandom { + unsigned int state; +} ControlRandom; + +hv_size_t cRandom_init(ControlRandom *o, int seed); + +void cRandom_onMessage(HvBase *_c, ControlRandom *o, int letIndex, const HvMessage *m, + void (*sendMessage)(HvBase *, int, const HvMessage *)); + +#endif // _HEAVY_CONTROL_RANDOM_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlSystem.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlSystem.h" +#include "HvTable.h" + +void cSystem_onMessage(HvBase *_c, void *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + + HvMessage *n = HV_MESSAGE_ON_STACK(1); + if (msg_compareSymbol(m, 0, "samplerate")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) ctx_getSampleRate(_c)); + } else if (msg_compareSymbol(m, 0, "numInputChannels")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) ctx_getNumInputChannels(_c)); + } else if (msg_compareSymbol(m, 0, "numOutputChannels")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) ctx_getNumOutputChannels(_c)); + } else if (msg_compareSymbol(m, 0, "currentTime")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) msg_getTimestamp(m)); + } else if (msg_compareSymbol(m, 0, "table")) { + // NOTE(mhroth): no need to check message format for symbols as table lookup will fail otherwise + HvTable *o = ctx_getTableForHash(_c, msg_getHash(m,1)); + if (o != NULL) { + if (msg_compareSymbol(m, 2, "length")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getLength(o)); + } else if (msg_compareSymbol(m, 2, "size")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o)); + } else if (msg_compareSymbol(m, 2, "head")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(o)); + } else return; + } else return; + } else return; + sendMessage(_c, 0, n); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlSystem.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_SYSTEM_H_ +#define _HEAVY_CONTROL_SYSTEM_H_ + +#include "HvBase.h" + +void cSystem_onMessage(HvBase *_c, void *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +#endif // _HEAVY_CONTROL_SYSTEM_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlUnop.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlUnop.h" +#include "HvBase.h" + +void cUnop_onMessage(HvBase *_c, UnopType op, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const )) { + if (msg_isFloat(m, 0)) { + float f = msg_getFloat(m, 0); + switch (op) { + case HV_UNOP_SIN: f = hv_sin_f(f); break; + case HV_UNOP_SINH: f = hv_sinh_f(f); break; + case HV_UNOP_COS: f = hv_cos_f(f); break; + case HV_UNOP_COSH: f = hv_cosh_f(f); break; + case HV_UNOP_TAN: f = hv_tan_f(f); break; + case HV_UNOP_TANH: f = hv_tanh_f(f); break; + case HV_UNOP_ASIN: f = hv_asin_f(f); break; + case HV_UNOP_ASINH: f = hv_asinh_f(f); break; + case HV_UNOP_ACOS: f = hv_acos_f(f); break; + case HV_UNOP_ACOSH: f = hv_acosh_f(f); break; + case HV_UNOP_ATAN: f = hv_atan_f(f); break; + case HV_UNOP_ATANH: f = hv_atanh_f(f); break; + case HV_UNOP_EXP: f = hv_exp_f(f); break; + case HV_UNOP_ABS: f = hv_abs_f(f); break; + case HV_UNOP_SQRT: f = (f > 0.0f) ? hv_sqrt_f(f) : 0.0f; break; + case HV_UNOP_LOG: f = (f > 0.0f) ? hv_log_f(f) : 0.0f; break; + case HV_UNOP_LOG2: f = (f > 0.0f) ? hv_log2_f(f) : 0.0f; break; + case HV_UNOP_LOG10: f = (f > 0.0f) ? hv_log10_f(f) : 0.0f; break; + case HV_UNOP_CEIL: f = hv_ceil_f(f); break; + case HV_UNOP_FLOOR: f = hv_floor_f(f); break; + case HV_UNOP_ROUND: f = hv_round_f(f); break; + default: return; + } + HvMessage *n = HV_MESSAGE_ON_STACK(1); + msg_initWithFloat(n, m->timestamp, f); + sendMessage(_c, 0, n); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlUnop.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_UNOP_H_ +#define _HEAVY_CONTROL_UNOP_H_ + +struct HvBase; +struct HvMessage; + +typedef enum UnopType { + HV_UNOP_ASIN, + HV_UNOP_ASINH, + HV_UNOP_ACOS, + HV_UNOP_ACOSH, + HV_UNOP_ATAN, + HV_UNOP_ATANH, + HV_UNOP_SIN, + HV_UNOP_SINH, + HV_UNOP_COS, + HV_UNOP_COSH, + HV_UNOP_TAN, + HV_UNOP_TANH, + HV_UNOP_EXP, + HV_UNOP_ABS, + HV_UNOP_SQRT, + HV_UNOP_LOG, + HV_UNOP_LOG2, + HV_UNOP_LOG10, + HV_UNOP_CEIL, + HV_UNOP_FLOOR, + HV_UNOP_ROUND +} UnopType; + +void cUnop_onMessage(struct HvBase *_c, UnopType op, const struct HvMessage *const m, + void (*sendMessage)(struct HvBase *, int, const struct HvMessage *const)); + +#endif // _HEAVY_CONTROL_UNOP_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlVar.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlVar.h" + +hv_size_t cVar_init_f(ControlVar *o, float k) { + o->e.type = FLOAT; + o->e.data.f = k; + return 0; +} + +hv_size_t cVar_init_s(ControlVar *o, const char *s) { + o->e.type = HASH; + o->e.data.h = msg_symbolToHash(s); + return 0; +} + +void cVar_free(ControlVar *o) { + // nothing to do +} + +void cVar_onMessage(HvBase *_c, ControlVar *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + switch (letIn) { + case 0: { + switch (msg_getType(m,0)) { + case BANG: { + HvMessage *n = HV_MESSAGE_ON_STACK(1); + if (o->e.type == FLOAT) msg_initWithFloat(n, msg_getTimestamp(m), o->e.data.f); + else if (o->e.type == HASH) msg_initWithHash(n, msg_getTimestamp(m), o->e.data.h); + else return; + sendMessage(_c, 0, n); + break; + } + case FLOAT: { + o->e.type = FLOAT; + o->e.data.f = msg_getFloat(m,0); + sendMessage(_c, 0, m); + break; + } + case SYMBOL: + case HASH: { + o->e.type = HASH; + o->e.data.h = msg_getHash(m,0); + sendMessage(_c, 0, m); + break; + } + default: return; + } + break; + } + case 1: { + switch (msg_getType(m,0)) { + case FLOAT: { + o->e.type = FLOAT; + o->e.data.f = msg_getFloat(m,0); + break; + } + case SYMBOL: + case HASH: { + o->e.type = HASH; + o->e.data.h = msg_getHash(m,0); + break; + } + default: break; + } + } + default: return; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/ControlVar.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_VAR_H_ +#define _HEAVY_CONTROL_VAR_H_ + +#include "HvBase.h" + +typedef struct ControlVar { + Element e; // type is only every FLOAT or HASH +} ControlVar; + +hv_size_t cVar_init_f(ControlVar *o, float k); + +hv_size_t cVar_init_s(ControlVar *o, const char *s); + +void cVar_free(ControlVar *o); + +void cVar_onMessage(HvBase *_c, ControlVar *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +#endif // _HEAVY_CONTROL_VAR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Heavy.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvBase.h" +#include "HvTable.h" + +#if !HV_WIN +#pragma mark - Heavy Table +#endif + +int hv_table_resize(HvTable *o, hv_uint32_t newLength) { + return hTable_resize(o, newLength); +} + +float *hv_table_getBuffer(HvTable *o) { + return hTable_getBuffer(o); +} + +hv_size_t hv_table_getLength(HvTable *o) { + return hTable_getLength(o); +} + + + +#if !HV_WIN +#pragma mark - Heavy Message +#endif + +hv_size_t hv_msg_getByteSize (hv_uint32_t numElements) { + return msg_getByteSize(numElements); +} + +void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) { + msg_init(m, numElements, timestamp); +} + +hv_size_t hv_msg_getNumElements(const HvMessage *const m) { + return msg_getNumElements(m); +} + +double hv_msg_getTimestamp(const HvMessage *const m) { + return msg_getTimestamp(m); +} + +void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) { + msg_setTimestamp(m, timestamp); +} + +bool hv_msg_isBang(const HvMessage *const m, int i) { + return msg_isBang(m,i); +} + +void hv_msg_setBang(HvMessage *m, int i) { + msg_setBang(m,i); +} + +bool hv_msg_isFloat(const HvMessage *const m, int i) { + return msg_isFloat(m, i); +} + +float hv_msg_getFloat(const HvMessage *const m, int i) { + return msg_getFloat(m,i); +} + +void hv_msg_setFloat(HvMessage *m, int i, float f) { + msg_setFloat(m,i,f); +} + +bool hv_msg_isSymbol(const HvMessage *const m, int i) { + return msg_isSymbol(m,i); +} + +char *hv_msg_getSymbol(const HvMessage *const m, int i) { + return msg_getSymbol(m,i); +} + +void hv_msg_setSymbol(HvMessage *m, int i, char *s) { + msg_setSymbol(m,i,s); +} + +bool hv_msg_isHash(const HvMessage *const m, int i) { + return msg_isHash(m, i); +} + +unsigned int hv_msg_getHash(const HvMessage *const m, int i) { + return msg_getHash(m, i); +} + +bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) { + return msg_hasFormat(m, fmt); +} + +char *hv_msg_toString(const HvMessage *const m) { + return msg_toString(m); +} + +HvMessage *hv_msg_copy(HvMessage *m) { + return msg_copy(m); +} + +void hv_msg_free(HvMessage *m) { + msg_free(m); +} + + + +#if !HV_WIN +#pragma mark - Heavy Common +#endif + +double hv_getSampleRate(HvBase *c) { + return ctx_getSampleRate(c); +} + +int hv_getNumInputChannels(HvBase *c) { + return ctx_getNumInputChannels(c); +} + +int hv_getNumOutputChannels(HvBase *c) { + return ctx_getNumOutputChannels(c); +} + +const char *hv_getName(HvBase *c) { + return ctx_getName(c); +} + +void hv_setPrintHook(HvBase *c, void (*f)(double, const char *, const char *, void *)) { + ctx_setPrintHook(c, f); +} + +void hv_setSendHook(HvBase *c, void (*f)(double, const char *, const HvMessage *const, void *)) { + ctx_setSendHook(c, f); +} + +void hv_vscheduleMessageForReceiver(HvBase *c, const char *receiverName, const double delayMs, const char *format, ...) { + va_list ap; + va_start(ap, format); + + const int numElem = (int) hv_strlen(format); + HvMessage *m = HV_MESSAGE_ON_STACK(numElem); + msg_init(m, numElem, c->blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*ctx_getSampleRate(c)/1000.0)); + for (int i = 0; i < numElem; i++) { + switch (format[i]) { + case 'b': msg_setBang(m,i); break; + case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; + case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; + default: break; + } + } + ctx_scheduleMessageForReceiver(c, receiverName, m); + + va_end(ap); +} + +void hv_scheduleMessageForReceiver(HvBase *c, const char *receiverName, double delayMs, HvMessage *m) { + hv_assert(delayMs >= 0.0); + msg_setTimestamp(m, c->blockStartTimestamp + (hv_uint32_t) (delayMs*ctx_getSampleRate(c)/1000.0)); + ctx_scheduleMessageForReceiver(c, receiverName, m); +} + +HvTable *hv_getTableForName(HvBase *c, const char *tableName) { + return ctx_getTableForName(c, tableName); +} + +void hv_cancelMessage(HvBase *c, HvMessage *m) { + ctx_cancelMessage(c, m, NULL); +} + +double hv_getCurrentTime(HvBase *c) { + return ((double) c->blockStartTimestamp)/c->sampleRate; +} + +void *hv_getUserData(HvBase *c) { + return ctx_getUserData(c); +} + +void hv_setUserData(HvBase *c, void *userData) { + ctx_setUserData(c, userData); +} + +void hv_setBasePath(HvBase *c, const char *basePath) { + ctx_setBasePath(c, basePath); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HeavyMath.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,645 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_MATH_H_ +#define _HEAVY_MATH_H_ + +#include "Utils.h" + +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/ +// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html +// http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html + +static inline void __hv_zero_f(hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + *bOut = _mm_setzero_ps(); +#elif HV_SIMD_NEON + *bOut = vdupq_n_f32(0.0f); +#else // HV_SIMD_NONE + *bOut = 0.0f; +#endif +} + +static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_load_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_load_ps(bIn); +#elif HV_SIMD_NEON + *bOut = vld1q_f32(bIn); +#else // HV_SIMD_NONE + *bOut = *bIn; +#endif +} + +static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) { +#if HV_SIMD_AVX + _mm256_store_ps(bOut, bIn); +#elif HV_SIMD_SSE + _mm_store_ps(bOut, bIn); +#elif HV_SIMD_NEON + vst1q_f32(bOut, bIn); +#else // HV_SIMD_NONE + *bOut = bIn; +#endif +} + +static inline void __hv_log_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_log_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_log_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_log_f() not implemented +#else // HV_SIMD_NONE + *bOut = (bIn > 0.0f) ? hv_log_f(bIn) : 0.0f; +#endif +} + +static inline void __hv_log10_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_log10_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_log10_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_log10_f() not implemented +#else // HV_SIMD_NONE + *bOut = (bIn > 0.0f) ? hv_log10_f(bIn) : 0.0f; +#endif +} + +static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_log2_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_log2_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_log2_f() not implemented +#else // HV_SIMD_NONE + *bOut = (bIn > 0.0f) ? hv_log2_f(bIn) : 0.0f; +#endif +} + +// NOTE(mhroth): this is a pretty ghetto implementation +static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_set_ps( + hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]), + hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0])); +#elif HV_SIMD_SSE + *bOut = _mm_set_ps(hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0])); +#elif HV_SIMD_NEON + *bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])}; +#else // HV_SIMD_NONE + *bOut = hv_cos_f(bIn); +#endif +} + +static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_acos_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_acos_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_acos_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_acos_f(bIn); +#endif +} + +static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_cosh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_cosh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_cosh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_cosh_f(bIn); +#endif +} + +static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_acosh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_acosh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_acosh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_acosh_f(bIn); +#endif +} + +static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_sin_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_sin_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_sin_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_sin_f(bIn); +#endif +} + +static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_asin_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_asin_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_asin_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_asin_f(bIn); +#endif +} + +static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_sinh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_sinh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_sinh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_sinh_f(bIn); +#endif +} + +static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_asinh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_asinh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_asinh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_asinh_f(bIn); +#endif +} + +static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_tan_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_tan_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_tan_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_tan_f(bIn); +#endif +} + +static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_atan_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_atan_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_atan_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_atan_f(bIn); +#endif +} + +static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_atan2_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_atan2_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_atan2_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_atan2_f(bIn0, bIn1); +#endif +} + +static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_tanh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_tanh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_tanh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_tanh_f(bIn); +#endif +} + +static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_atanh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_atanh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_atanh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_atanh_f(bIn); +#endif +} + +// NOTE(mhroth): use of sqrt is absolute and total MURDER. Make do with recipocal sqrt if possible!! +static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_sqrt_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_sqrt_ps(bIn); +#elif HV_SIMD_NEON +#warning __hv_sqrt_f() numerical results may be inexact + *bOut = vrecpeq_f32(vrsqrteq_f32(bIn)); +#else // HV_SIMD_NONE + *bOut = hv_sqrt_f(bIn); +#endif +} + +static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_rsqrt_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_rsqrt_ps(bIn); +#elif HV_SIMD_NEON +#warning __hv_rsqrt_f() numerical results may be inexact + *bOut = vrsqrteq_f32(bIn); +#else // HV_SIMD_NONE + *bOut = 1.0f/hv_sqrt_f(bIn); +#endif +} + +static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn); +#elif HV_SIMD_SSE + *bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31 +#elif HV_SIMD_NEON + *bOut = vabsq_f32(bIn); +#else // HV_SIMD_NONE + *bOut = hv_abs_f(bIn); +#endif +} + +static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_exp_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_exp_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_exp_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_exp_f(bIn); +#endif +} + +static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_ceil_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_ceil_ps(bIn); +#elif HV_SIMD_NEON +#if __ARM_ARCH >= 8 + *bOut = vrndpq_f32(bIn); +#else +#warning A slow NEON implementation of __hv_ceil_f() is being used because the necessary intrinsic cannot be found. It is only available in ARMv8. + *bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])}; +#endif // vrndpq_f32 +#else // HV_SIMD_NONE + *bOut = hv_ceil_f(bIn); +#endif +} + +static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_floor_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_floor_ps(bIn); +#elif HV_SIMD_NEON +#if __ARM_ARCH >= 8 + *bOut = vrndmq_f32(bIn); +#else +#warning A slow NEON implementation of __hv_floor_f() is being used because the necessary intrinsic cannot be found. It is only available in ARMv8. + *bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])}; +#endif // vrndmq_f32 +#else // HV_SIMD_NONE + *bOut = hv_floor_f(bIn); +#endif +} + +// __add~f +static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_add_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_add_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vaddq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 + bIn1; +#endif +} + +// __add~i +static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_add_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vaddq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 + bIn1; +#endif +} + +// __sub~f +static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_sub_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_sub_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vsubq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 - bIn1; +#endif +} + +// __mul~f +static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_mul_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_mul_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmulq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 * bIn1; +#endif +} + +// __*~i +static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_mullo_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmulq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 * bIn1; +#endif +} + +// __cast~if +static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cvtepi32_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_cvtepi32_ps(bIn); +#elif HV_SIMD_NEON + *bOut = vcvtq_f32_s32(bIn); +#else // HV_SIMD_NONE + *bOut = (float) bIn; +#endif +} + +// __cast~fi +static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cvtps_epi32(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_cvtps_epi32(bIn); +#elif HV_SIMD_NEON + *bOut = vcvtq_s32_f32(bIn); +#else // HV_SIMD_NONE + *bOut = (int) bIn; +#endif +} + +static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_div_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_div_ps(bIn0, bIn1); +#elif HV_SIMD_NEON +#warning __hv_div_f() numerical results may be inexact + *bOut = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f; +#endif +} + +static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_min_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_min_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vminq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_min_f(bIn0, bIn1); +#endif +} + +static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_min_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vminq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_min_i(bIn0, bIn1); +#endif +} + +static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_max_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_max_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmaxq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_max_f(bIn0, bIn1); +#endif +} + +static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_max_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmaxq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_max_i(bIn0, bIn1); +#endif +} + +static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_set_ps( + hv_pow_f(bIn0[7], bIn1[7]), + hv_pow_f(bIn0[6], bIn1[6]), + hv_pow_f(bIn0[5], bIn1[5]), + hv_pow_f(bIn0[4], bIn1[4]), + hv_pow_f(bIn0[3], bIn1[3]), + hv_pow_f(bIn0[2], bIn1[2]), + hv_pow_f(bIn0[1], bIn1[1]), + hv_pow_f(bIn0[0], bIn1[0])); +#elif HV_SIMD_SSE + *bOut = _mm_set_ps( + hv_pow_f(bIn0[3], bIn1[3]), + hv_pow_f(bIn0[2], bIn1[2]), + hv_pow_f(bIn0[1], bIn1[1]), + hv_pow_f(bIn0[0], bIn1[0])); +#elif HV_SIMD_NEON + *bOut = (float32x4_t) { + hv_pow_f(bIn0[0], bIn1[0]), + hv_pow_f(bIn0[1], bIn1[1]), + hv_pow_f(bIn0[2], bIn1[2]), + hv_pow_f(bIn0[3], bIn1[3])}; +#else // HV_SIMD_NONE + *bOut = hv_pow_f(bIn0, bIn1); +#endif +} + +static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmpgt_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 > bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmpge_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmplt_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 < bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmple_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmpneq_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1))); +#else // HV_SIMD_NONE + *bOut = (bIn0 != bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_xor_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_xor_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_xor_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_xor_f() not implemented +#else // HV_SIMD_NONE + *bOut = (float) (((int) bIn0) ^ ((int) bIn1)); +#endif +} + +static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_and_ps(bIn1, bIn0); +#elif HV_SIMD_SSE + *bOut = _mm_and_ps(bIn1, bIn0); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0))); +#else // HV_SIMD_NONE + if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f; + else if (bIn0 == 1.0f) *bOut = bIn1; + else if (bIn1 == 1.0f) *bOut = bIn0; + else hv_assert(0); // TODO(mhroth): floating point & is pretty much a bad idea, only used for if~ +#endif +} + +// bOut = (bIn0 * bIn1) + bIn2 +static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#if HV_SIMD_FMA + *bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2); +#else + *bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2); +#endif // HV_SIMD_FMA +#elif HV_SIMD_SSE +#if HV_SIMD_FMA + *bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2); +#else + *bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2); +#endif // HV_SIMD_FMA +#elif HV_SIMD_NEON +#if __ARM_ARCH >= 8 + *bOut = vfmaq_f32(bIn2, bIn0, bIn1); +#else + // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures + // But in fact ideally fma would be disabled in ir2c for ARM architectures. + // LLVM does a much better job handling fma than we do. + *bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2); +#endif +#else // HV_SIMD_NONE + *bOut = hv_fma_f(bIn0, bIn1, bIn2); +#endif +} + +#endif // _HEAVY_MATH_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Heavy_bbb.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,241 @@ + +/** + * Copyright (c) 2014,2015 Enzien Audio, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or + * sublicense copies of the Software, strictly on a non-commercial basis, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * DO NOT MODIFY. THIS CODE IS MACHINE GENERATED BY THE SECTION6 HEAVY COMPILER. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Utils.h" + +#if !HV_MSVC +#pragma mark - Heavy Table +#endif + +#ifndef _HEAVY_TABLE_H_ +#define _HEAVY_TABLE_H_ + +typedef struct HvTable HvTable; + +/** + * Resizes the table to the given length. Length must be positive. + * Existing contents are copied to the new table. Remaining space is cleared. + * The change in byte-size of the table is returned. A value of zero indicates error. + */ +HV_EXPORT int hv_table_resize(HvTable *o, hv_uint32_t newLength); + +/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */ +HV_EXPORT float *hv_table_getBuffer(HvTable *o); + +/** Returns the length of this table in samples. */ +HV_EXPORT int hv_table_getLength(HvTable *o); + +#endif // _HEAVY_TABLE_H_ + + + +#if !HV_MSVC +#pragma mark - Heavy Message +#endif + +#ifndef _HEAVY_MESSAGE_H_ +#define _HEAVY_MESSAGE_H_ + +HV_EXPORT typedef struct HvMessage HvMessage; + +/** Returns the byte size of a HvMessage with a number of elements on the heap. */ +HV_EXPORT hv_size_t hv_msg_getByteSize(int numElements); + +/** Create a HvMessage on the stack with a number of elements. This message MUST NOT be freed. */ +#define hv_msg_onStack(_n) ((HvMessage *) hv_alloca(hv_msg_getByteSize(_n))) + +/** Initialise a message with the number of elements and a timestamp (in milliseconds). */ +HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, double timestamp); + +/** Returns the number of elements in this message. */ +HV_EXPORT int hv_msg_getNumElements(const HvMessage *const m); + +/** Returns the time at which this message exists (in milliseconds). */ +HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *const m); + +/** Set the time at which this message should be executed (in milliseconds). */ +HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp); + +/** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i); + +/** Sets the indexed element to a bang. Index is not bounds checked. */ +HV_EXPORT void hv_msg_setBang(HvMessage *m, int i); + +/** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i); + +/** Returns the indexed element as a float value. Index is not bounds checked. */ +HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i); + +/** Sets the indexed element to float value. Index is not bounds checked. */ +HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f); + +/** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i); + +/** Returns the indexed element as a symbol value. Index is not bounds checked. */ +HV_EXPORT char *hv_msg_getSymbol(const HvMessage *const m, int i); + +/** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i); + +/** Returns the indexed element as a hash value. Index is not bounds checked. */ +HV_EXPORT unsigned int hv_msg_getHash(const HvMessage *const m, int i); + +/** Sets the indexed element to symbol value. Index is not bounds checked. */ +HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s); + +/** + * Returns true if the message has the given format, in number of elements and type. False otherwise. + * Valid element types are: + * 'b': bang + * 'f': float + * 's': symbol + * + * For example, a message with three floats would have a format of "fff". A single bang is "b". + * A message with two symbols is "ss". These types can be mixed and matched in any way. + */ +HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt); + +/** + * Returns a basic string representation of the message. + * The character array MUST be deallocated by the caller. + */ +HV_EXPORT char *hv_msg_toString(const HvMessage *const m); + +/** Copy a message onto the stack. The message persists. */ +HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m); + +/** Free a copied message. */ +HV_EXPORT void hv_msg_free(HvMessage *m); + +#endif // _HEAVY_MESSAGE_H_ + + + +#if !HV_MSVC +#pragma mark - Heavy Patch +#endif + +#ifndef _HEAVY_BBB_H_ +#define _HEAVY_BBB_H_ + +typedef struct Hv_bbb Hv_bbb; + +/** + * Creates a new patch instance. + * Sample rate should be positive and in Hertz. + */ +HV_EXPORT Hv_bbb *hv_bbb_new(double sampleRate); + +/** + * Creates a new patch instance. + * Sample rate should be positive and in Hertz. + * Pool size is in kilobytes, and determines the maximum amount of memory + * allocated to messages at any time. By default this is 10. + */ +HV_EXPORT Hv_bbb *hv_bbb_new_with_pool(double sampleRate, int poolKb); + +/** Frees a patch instance. */ +HV_EXPORT void hv_bbb_free(Hv_bbb *c); + +/** Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays. */ +HV_EXPORT int hv_bbb_process(Hv_bbb *c, float **const inputBuffers, float **const outputBuffers, int n4); + +/** Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels. */ +HV_EXPORT int hv_bbb_process_inline(Hv_bbb *c, float *const inputBuffers, float *const outputBuffers, int n4); + +/** Processes one block of samples for a patch instance. The buffer format is an interleaved short array of channels. */ +HV_EXPORT int hv_bbb_process_inline_short(Hv_bbb *c, short *const inputBuffers, short *const outputBuffers, int n4); +#endif // _HEAVY_BBB_H_ + + + +#if !HV_MSVC +#pragma mark - Heavy Common +#endif + +#ifndef _HEAVY_COMMON_H_ +#define _HEAVY_COMMON_H_ + +typedef void Heavy; + +/** Returns the sample rate with which this patch has been configured. */ +HV_EXPORT double hv_getSampleRate(Heavy *c); + +/** Returns the number of input channels with which this patch has been configured. */ +HV_EXPORT int hv_getNumInputChannels(Heavy *c); + +/** Returns the number of output channels with which this patch has been configured. */ +HV_EXPORT int hv_getNumOutputChannels(Heavy *c); + +/** Set the print hook. The function is called whenever a message is sent to a print object. */ +HV_EXPORT void hv_setPrintHook(Heavy *c, + void (*f)(double timestamp, const char *printName, const char *message, void *userData)); + +/** + * Set the send hook. The function is called whenever a message is sent to any send object. + * Messages returned by this function should NEVER be freed. If the message must persist, call + * hv_msg_copy() first. + */ +HV_EXPORT void hv_setSendHook(Heavy *c, void (*f)(double timestamp, const char *receiverName, const HvMessage *const m, void *userData)); + +HV_EXPORT void hv_vscheduleMessageForReceiver( + Heavy *c, const char *receiverName, double delayMs, const char *format, ...); + +HV_EXPORT void hv_scheduleMessageForReceiver(Heavy *c, const char *receiverName, double delayMs, HvMessage *m); + +/** Cancels a previously scheduled message. */ +HV_EXPORT void hv_cancelMessage(Heavy *c, HvMessage *m); + +/** Returns a table object given its name. NULL if no table with that name exists. */ +HV_EXPORT HvTable *hv_getTableForName(Heavy *c, const char *tableName); + +/** Returns the current patch time in milliseconds. */ +HV_EXPORT double hv_getCurrentTime(Heavy *c); + +/** Sets a user-definable value. This value is never manipulated by Heavy. */ +HV_EXPORT void hv_setUserData(Heavy *c, void *userData); + +/** Returns the user-defined data. */ +HV_EXPORT void *hv_getUserData(Heavy *c); + +/** Define the base path of the patch. Used as the root path to locate assets. */ +HV_EXPORT void hv_setBasePath(Heavy *c, const char *basePath); + +/** Returns the read-only user-assigned name of this patch. */ +HV_EXPORT const char *hv_getName(Heavy *c); + +#endif // _HEAVY_COMMON_H_ + +#ifdef __cplusplus +} // extern "C" +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvBase.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvBase.h" + +void ctx_setBasePath(HvBase *const _c, const char *basePath) { + hv_free(_c->basePath); + if (basePath != NULL) { + hv_size_t len = (hv_size_t) hv_strlen(basePath); + _c->basePath = (char *) hv_malloc((len+1)*sizeof(char)); + hv_strncpy(_c->basePath, basePath, len); + } +} + +void ctx_cancelMessage(HvBase *_c, HvMessage *m, void (*sendMessage)(HvBase *, int, const HvMessage *)) { + mq_removeMessage(&_c->mq, m, sendMessage); +} + +void ctx_scheduleMessageForReceiverV(HvBase *const _c, const char *name, + const hv_uint32_t timestamp, const char *format, ...) { + va_list ap; + va_start(ap, format); + + const int numElem = (int) hv_strlen(format); + HvMessage *m = HV_MESSAGE_ON_STACK(numElem); + msg_init(m, numElem, timestamp); + for (int i = 0; i < numElem; i++) { + switch (format[i]) { + case 'b': msg_setBang(m,i); break; + case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; + case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; + default: break; + } + } + _c->f_scheduleMessageForReceiver(_c, name, m); + + va_end(ap); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvBase.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_BASE_H_ +#define _HEAVY_BASE_H_ + +#include "MessageQueue.h" +#include "Utils.h" + +#define Base(_x) ((HvBase *) _x) + +typedef struct HvBase { + int numInputChannels; + int numOutputChannels; + double sampleRate; + hv_uint32_t blockStartTimestamp; + unsigned int numBytes; // the total number of bytes allocated for this patch + void (*f_scheduleMessageForReceiver)(struct HvBase *const, const char *, HvMessage *); + struct HvTable *(*f_getTableForHash)(struct HvBase *const, hv_uint32_t); + MessageQueue mq; + void (*printHook)(double, const char *, const char *, void *); + void (*sendHook)(double, const char *, const HvMessage *const, void *); + char *basePath; + void *userData; + const char *name; +} HvBase; + +/** + * Schedule a message in the message queue according to its timestamp. + * The copy of the message added to the queue is returned. + */ +static inline HvMessage *ctx_scheduleMessage(HvBase *_c, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *), int outletIndex) { + return mq_addMessageByTimestamp(&_c->mq, (HvMessage *) m, outletIndex, sendMessage); +} + +static inline void ctx_scheduleMessageForReceiver(HvBase *const _c, + const char *name, HvMessage *m) { + _c->f_scheduleMessageForReceiver(_c, name, m); +} + +void ctx_scheduleMessageForReceiverV(HvBase *const _c, const char *name, + const hv_uint32_t timestamp, const char *format, ...); + +void ctx_cancelMessage(HvBase *_c, HvMessage *m, + void (*sendMessage)(HvBase *, int, const HvMessage *)); + +static inline int ctx_millisecondsToSamples(HvBase *_c, float timeInMs) { + return (int) (timeInMs * _c->sampleRate / 1000.0); +} + +static inline double ctx_samplesToMilliseconds(HvBase *_c, int samples) { + return 1000.0 * samples / _c->sampleRate; +} + +static inline double ctx_getSampleRate(HvBase *_c) { + return _c->sampleRate; +} + +static inline int ctx_getNumInputChannels(HvBase *_c) { + return _c->numInputChannels; +} + +static inline int ctx_getNumOutputChannels(HvBase *_c) { + return _c->numOutputChannels; +} + +static inline const char *ctx_getName(HvBase *_c) { + return _c->name; +} + +/** Returns the first sample of the block. */ +static inline hv_uint32_t ctx_getBlockStartTimestamp(HvBase *_c) { + return _c->blockStartTimestamp; +} + +static inline void ctx_setPrintHook(HvBase *const _c, void (*f)(double, + const char *, const char *, void *)) { + _c->printHook = f; +} + +static inline void ctx_setSendHook(HvBase *const _c, void (*f)(double, const char *, const HvMessage *const, void *)) { + _c->sendHook = f; +} + +static inline void *ctx_getUserData(HvBase *const _c) { + return _c->userData; +} + +static inline void ctx_setUserData(HvBase *const _c, void *userData) { + _c->userData = userData; +} + +void ctx_setBasePath(HvBase *const _c, const char *basePath); + +static inline const char *ctx_getBasePath(HvBase *const _c) { + return _c->basePath; +} + +static inline struct HvTable *ctx_getTableForHash(HvBase *const _c, hv_uint32_t h) { + return _c->f_getTableForHash(_c, h); +} + +static inline struct HvTable *ctx_getTableForName(HvBase *const _c, const char *tableName) { + return ctx_getTableForHash(_c, msg_symbolToHash(tableName)); +} + +/** Returns the total number of bytes allocated for this patch. */ +static inline unsigned int ctx_getNumBytes(HvBase *_c) { + return _c->numBytes; +} + +#endif // _HEAVY_BASE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvContext_bbb.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,215 @@ + +/** + * Copyright (c) 2014,2015 Enzien Audio, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or + * sublicense copies of the Software, strictly on a non-commercial basis, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * DO NOT MODIFY. THIS CODE IS MACHINE GENERATED BY THE SECTION6 HEAVY COMPILER. + */ + +/* + * System Includes + */ + +#include <assert.h> +#include <math.h> +#include <string.h> +#include <stdarg.h> +#include "HvContext_bbb.h" +#include "HeavyMath.h" + + +/* + * Function Declarations + */ + + + +/* + * Static Helper Functions + */ + +static void ctx_intern_scheduleMessageForReceiver( + HvBase *const _c, const char *name, HvMessage *m) { + switch (msg_symbolToHash(name)) { + default: return; + } +} + +static struct HvTable *ctx_intern_getTableForHash(HvBase *const _c, hv_uint32_t h) { + switch (h) { + default: return NULL; + } +} + + + +/* + * Context Include and Implementatons + */ + +Hv_bbb *hv_bbb_new_with_pool(double sampleRate, int poolKb) { + hv_assert(sampleRate > 0.0); // can't initialise with sampling rate of 0 + hv_assert(poolKb >= 1); // a message pool of some reasonable size is always needed + Hv_bbb *const _c = (Hv_bbb *) hv_malloc(sizeof(Hv_bbb)); + + Base(_c)->numInputChannels = 0; + Base(_c)->numOutputChannels = 2; + Base(_c)->sampleRate = sampleRate; + Base(_c)->blockStartTimestamp = 0; + Base(_c)->f_scheduleMessageForReceiver = &ctx_intern_scheduleMessageForReceiver; + Base(_c)->f_getTableForHash = &ctx_intern_getTableForHash; + mq_initWithPoolSize(&Base(_c)->mq, poolKb); + Base(_c)->basePath = NULL; + Base(_c)->printHook = NULL; + Base(_c)->sendHook = NULL; + Base(_c)->userData = NULL; + Base(_c)->name = "bbb"; + + Base(_c)->numBytes = sizeof(Hv_bbb); + Base(_c)->numBytes += sPhasor_k_init(&_c->sPhasor_O587H, 440.0f, sampleRate); + + // loadbang + + return _c; +} + +Hv_bbb *hv_bbb_new(double sampleRate) { + return hv_bbb_new_with_pool(sampleRate, 10); // default to 10KB MessagePool +} + +void hv_bbb_free(Hv_bbb *_c) { + + hv_free(Base(_c)->basePath); + mq_free(&Base(_c)->mq); // free queue after all objects have been freed, messages may be cancelled + + hv_free(_c); +} + + + +/* + * Static Function Implementation + */ + + + +/* + * Context Process Implementation + */ + +int hv_bbb_process(Hv_bbb *const _c, float **const inputBuffers, float **const outputBuffers, int nx) { + const int n4 = nx & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD + + // temporary signal vars + hv_bufferf_t Bf0, Bf1, Bf2, Bf3, Bf4; + + // input and output vars + hv_bufferf_t O0, O1; + + // declare and init the zero buffer + hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO)); + + hv_uint32_t nextBlock = Base(_c)->blockStartTimestamp; + for (int n = 0; n < n4; n += HV_N_SIMD) { + + // process all of the messages for this block + nextBlock += HV_N_SIMD; + while (mq_hasMessageBefore(&Base(_c)->mq, nextBlock)) { + MessageNode *const node = mq_peek(&Base(_c)->mq); + node->sendMessage(Base(_c), node->let, node->m); + mq_pop(&Base(_c)->mq); + } + + + + // zero output buffers + __hv_zero_f(VOf(O0)); + __hv_zero_f(VOf(O1)); + + // process all signal functions + __hv_phasor_k_f(&_c->sPhasor_O587H, VOf(Bf0)); + __hv_var_k_f(VOf(Bf1), 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0); + __hv_sub_f(VIf(Bf0), VIf(Bf1), VOf(Bf1)); + __hv_abs_f(VIf(Bf1), VOf(Bf1)); + __hv_var_k_f(VOf(Bf0), 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0); + __hv_sub_f(VIf(Bf1), VIf(Bf0), VOf(Bf0)); + __hv_var_k_f(VOf(Bf1), 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 0); + __hv_mul_f(VIf(Bf0), VIf(Bf1), VOf(Bf1)); + __hv_mul_f(VIf(Bf1), VIf(Bf1), VOf(Bf0)); + __hv_mul_f(VIf(Bf1), VIf(Bf0), VOf(Bf2)); + __hv_mul_f(VIf(Bf2), VIf(Bf0), VOf(Bf0)); + __hv_var_k_f(VOf(Bf3), 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0); + __hv_var_k_f(VOf(Bf4), 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0); + __hv_mul_f(VIf(Bf2), VIf(Bf4), VOf(Bf4)); + __hv_sub_f(VIf(Bf1), VIf(Bf4), VOf(Bf4)); + __hv_fma_f(VIf(Bf0), VIf(Bf3), VIf(Bf4), VOf(Bf4)); + __hv_var_k_f(VOf(Bf3), 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0); + __hv_mul_f(VIf(Bf4), VIf(Bf3), VOf(Bf3)); + __hv_add_f(VIf(Bf3), VIf(O1), VOf(O1)); + __hv_add_f(VIf(Bf3), VIf(O0), VOf(O0)); + + // save output vars to output buffer + __hv_store_f(outputBuffers[0]+n, VIf(O0)); + __hv_store_f(outputBuffers[1]+n, VIf(O1)); + } + + Base(_c)->blockStartTimestamp = nextBlock; + + return n4; // return the number of frames processed +} + +int hv_bbb_process_inline(Hv_bbb *c, float *const inputBuffers, float *const outputBuffers, int n4) { + hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD + int i = ctx_getNumInputChannels(Base(c)); + float **bIn = (float **) hv_alloca(i*sizeof(float *)); + while (i--) bIn[i] = inputBuffers+(i*n4); + + i = ctx_getNumOutputChannels(Base(c)); + float **bOut = (float **) hv_alloca(i*sizeof(float *)); + while (i--) bOut[i] = outputBuffers+(i*n4); + + int n = hv_bbb_process(c, bIn, bOut, n4); + return n; +} + +int hv_bbb_process_inline_short(Hv_bbb *c, short *const inputBuffers, short *const outputBuffers, int n4) { + hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD + int numChannels = ctx_getNumInputChannels(Base(c)); + float *bIn = (float *) hv_alloca(numChannels*n4*sizeof(float)); + for (int i = 0; i < numChannels; ++i) { + for (int j = 0; j < n4; ++j) { + bIn[i*n4+j] = ((float) inputBuffers[i+numChannels*j]) * 0.00003051757813f; + } + } + + numChannels = ctx_getNumOutputChannels(Base(c)); + float *bOut = (float *) hv_alloca(numChannels*n4*sizeof(float)); + + int n = hv_bbb_process_inline(c, bIn, bOut, n4); + + for (int i = 0; i < numChannels; ++i) { + for (int j = 0; j < n4; ++j) { + outputBuffers[i+numChannels*j] = (short) (bOut[i*n4+j] * 32767.0f); + } + } + + return n; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvContext_bbb.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,46 @@ + +/** + * Copyright (c) 2014,2015 Enzien Audio, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or + * sublicense copies of the Software, strictly on a non-commercial basis, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * DO NOT MODIFY. THIS CODE IS MACHINE GENERATED BY THE SECTION6 HEAVY COMPILER. + */ + +#ifndef _HEAVYCONTEXT_BBB_H_ +#define _HEAVYCONTEXT_BBB_H_ + +#include "HvBase.h" + +#define Context(_x) ((Hv_bbb *) (_x)) + +// object includes +#include "SignalVar.h" +#include "SignalPhasor.h" +#include "HeavyMath.h" + +typedef struct Hv_bbb { + HvBase base; + + // objects + SignalPhasor sPhasor_O587H; +} Hv_bbb; + +#endif // _HEAVYCONTEXT_BBB_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvMessage.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,335 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvMessage.h" + +HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) { + m->timestamp = timestamp; + m->numElements = (hv_uint16_t) numElements; + m->numBytes = (hv_uint16_t) msg_getByteSize(numElements); + return m; +} + +HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setFloat(m, 0, f); + return m; +} + +HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setBang(m, 0); + return m; +} + +HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, char *s) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setSymbol(m, 0, s); + return m; +} + +HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setHash(m, 0, h); + return m; +} + +HvMessage *msg_initV(HvMessage *const m, const hv_uint32_t timestamp, const char *format, ...) { + va_list ap; + va_start(ap, format); + + const int numElem = (int) hv_strlen(format); + msg_init(m, numElem, timestamp); + for (int i = 0; i < numElem; i++) { + switch (format[i]) { + case 'b': msg_setBang(m,i); break; + case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; + case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; + case 'h': // hash not supported + default: break; + } + } + va_end(ap); + + return m; +} + +hv_size_t msg_getNumHeapBytes(const HvMessage *m) { + // get the size of all symbol elements + hv_size_t rsizeofsym = 0; + for (int i = 0; i < msg_getNumElements(m); ++i) { + if (msg_isSymbol(m,i)) { + rsizeofsym += (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // +1 to allow for trailing '\0' + } + } + + // the total byte size on the heap + return (msg_getByteSize(msg_getNumElements(m)) + rsizeofsym); +} + +void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) { + HvMessage *r = (HvMessage *) buffer; + + // assert that the message is not already larger than the length of the buffer + hv_assert(msg_getNumBytes(m) <= len); + + // copy the basic message to the buffer + hv_memcpy(r, m, msg_getNumBytes(m)); + + hv_size_t len_r = msg_getNumBytes(m); + + char *p = buffer + msg_getByteSize(msg_getNumElements(m)); // points to the end of the base message + for (int i = 0; i < msg_getNumElements(m); ++i) { + if (msg_isSymbol(m,i)) { + const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char + hv_assert(len_r + symLen <= len); // stay safe! + hv_strncpy(p, msg_getSymbol(m,i), symLen); + msg_setSymbol(r, i, p); + p += symLen; + len_r += symLen; + } + } + + r->numBytes = (hv_uint16_t) len_r; // update the message size in memory +} + +// the message is serialised such that all symbol elements are placed in order at the end of the buffer +HvMessage *msg_copy(const HvMessage *m) { + const hv_size_t heapSize = msg_getNumHeapBytes(m); + char *r = (char *) hv_malloc(heapSize); + msg_copyToBuffer(m, r, heapSize); + return (HvMessage *) r; +} + +void msg_free(HvMessage *m) { + hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message +} + +bool msg_hasFormat(const HvMessage *m, const char *fmt) { + if (fmt == NULL) return false; + if (msg_getNumElements(m) != hv_strlen(fmt)) return false; + for (int i = 0; i < msg_getNumElements(m); i++) { + switch (fmt[i]) { + case 'b': if (!msg_isBang(m, i)) return false; break; + case 'f': if (!msg_isFloat(m, i)) return false; break; + case 's': if (!msg_isSymbol(m, i)) return false; break; + case 'h': if (!msg_isHash(m, i)) return false; break; + default: return false; + } + } + return true; +} + +bool msg_compareSymbol(const HvMessage *m, int i, const char *s) { + switch (msg_getType(m,i)) { + case SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s); + case HASH: return (msg_getHash(m,i) == msg_symbolToHash(s)); + default: return false; + } +} + +bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) { + if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) { + if (msg_getType(m, i_m) == msg_getType(n, i_n)) { + switch (msg_getType(m, i_m)) { + case BANG: return true; + case FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n)); + case SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n)); + case HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n); + default: break; + } + } + } + return false; +} + +void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) { + switch (msg_getType(m, i_m)) { + case BANG: msg_setBang(n, i_n); break; + case FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break; + case SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break; + case HASH: msg_setHash(n, i_n, msg_getHash(m, i_m)); + default: break; + } +} + +hv_uint32_t msg_symbolToHash(const char *s) { + // this hash is based MurmurHash2 + // http://en.wikipedia.org/wiki/MurmurHash + // https://sites.google.com/site/murmurhash/ + static const unsigned int n = 0x5bd1e995; + static const int r = 24; + + int len = (int) hv_strlen(s); + hv_uint32_t x = (hv_uint32_t) (len); // seed (0) ^ len + + while (len >= 4) { + hv_uint32_t k = *((hv_uint32_t *)s); + k *= n; + k ^= k >> r; + k *= n; + x *= n; + x ^= k; + s += 4; len -= 4; + } + + switch(len) { + case 3: x ^= s[2] << 16; + case 2: x ^= s[1] << 8; + case 1: x ^= s[0]; x *= n; + default: break; + } + + x ^= x >> 13; + x *= n; + x ^= x >> 15; + + return x; +} + +hv_uint32_t msg_getHash(const HvMessage *const m, int i) { + hv_assert(i < msg_getNumElements(m)); // invalid index + switch (msg_getType(m,i)) { + case BANG: return 0xFFFFFFFF; + case FLOAT: { + float f = msg_getFloat(m,i); + return *((hv_uint32_t *) &f); + } + case SYMBOL: return msg_symbolToHash(msg_getSymbol(m,i)); + case HASH: return (&(m->elem)+i)->data.h; + default: return 0; + } +} + +char *msg_toString(const HvMessage *m) { + hv_assert(msg_getNumElements(m) > 0); + int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int)); + int size = 0; // the total length of our final buffer + + // loop through every element in our list of atoms + // first loop figures out how long our buffer should be + for (int i = 0; i < msg_getNumElements(m); i++) { + // length of our string is each atom plus a space, or \0 on the end + switch (msg_getType(m, i)) { + case BANG: len[i] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break; + case FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break; + case SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break; + case HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; break; + default: break; + } + size += len[i]; + } + + hv_assert(size > 0); + + // now we do the piecewise concatenation into our final string + // the final buffer we will pass back after concatenating all strings - user should free it + char *finalString = (char *) hv_malloc(size*sizeof(char)); + int pos = 0; + for (int i = 0; i < msg_getNumElements(m); i++) { + // put a string representation of each atom into the final string + switch (msg_getType(m, i)) { + case BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break; + case FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break; + case SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break; + case HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break; + default: break; + } + pos += len[i]; + finalString[pos-1] = 32; // ASCII space + } + finalString[size-1] = '\0'; // ensure that the string is null terminated + return finalString; +} + +/* + * TODO(mhroth): unnecessary for now +bool msg_resolveDollarArguments(HvMessage *m, HvMessage *n, int z, char *buf, hv_size_t len, const char *args, ...) { + va_list ap; + va_start(ap, args); + + hv_memset(buf, 0, len); // clear the buffer + hv_size_t j = 0; // position in buffer + const hv_size_t numArgs = hv_strlen(args); // the number of arguments + + // if there is only one argument then the result has the chance of being a number, otherwise no + bool isNumber = (numArgs == 1); + + for (hv_size_t i = 0; i < numArgs; ++i) { + switch (args[i]) { + case 'i': { // a message index + const int index = (int) va_arg(ap, int); + if (index < 0) { + // $0 always resolve to "0" + const hv_size_t x = 1; + if (x < len-j) { // always < in order to allow for trailing \0 + j += snprintf(buf+j, len-j, "0"); + } + } else { + switch (msg_getType(m, index)) { + default: + case BANG: break; // this case should never happen + case FLOAT: { + const hv_size_t x = snprintf(NULL, 0, "%g", msg_getFloat(m,index)); + if (x < len-j) { // ensure that the buffer is big enough + j += snprintf(buf+j, len-j, "%g", msg_getFloat(m,index)); + } + break; + } + case SYMBOL: { + const hv_size_t x = snprintf(NULL, 0, "%s", msg_getSymbol(m,index)); + if (x < len-j) { + j += snprintf(buf+j, len-j, "%s", msg_getSymbol(m,index)); + isNumber = false; + } + break; + } + } + } + break; + } + case 's': { // a string + const char *s = (char *) va_arg(ap, char *); + const hv_size_t x = snprintf(NULL, 0, "%s", s); + if (x <= len-j) { + j += snprintf(buf+j, len-j, "%s", s); + isNumber = false; + } + break; + } + default: break; + } + } + + if (isNumber) { + msg_setFloat(n,z,(float) atof(buf)); + } else { + msg_setSymbol(n,z,buf); + } + + va_end(ap); + + return !isNumber; +} +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvMessage.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_MESSAGE_H_ +#define _HEAVY_MESSAGE_H_ + +#include "Utils.h" + +typedef enum ElementType { + BANG, + FLOAT, + SYMBOL, + HASH +} ElementType; + +typedef struct Element { + ElementType type; + union { + float f; // float + char *s; // symbol + hv_uint32_t h; // hash + } data; +} Element; + +typedef struct HvMessage { + hv_uint32_t timestamp; // the sample at which this message should be processed + hv_uint16_t numElements; + hv_uint16_t numBytes; // the number of bytes that this message occupies in memory + Element elem; +} HvMessage; + +#define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getByteSize(_x)) + +/** Returns the total length in bytes of this message for a given number of elements. */ +static inline hv_size_t msg_getByteSize(hv_size_t numElements) { + hv_assert(numElements > 0); + return sizeof(HvMessage) + ((numElements-1) * sizeof(Element)); +} + +HvMessage *msg_copy(const HvMessage *m); + +/** Returns the number of bytes that this message would occupy on the heap. */ +hv_size_t msg_getNumHeapBytes(const HvMessage *m); + +/** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */ +void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len); + +void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM); + +/** Frees a message on the heap. Does nothing if argument is NULL. */ +void msg_free(HvMessage *m); + +HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp); + +HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f); + +HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp); + +HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, char *s); + +HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h); + +HvMessage *msg_initV(HvMessage *const m, const hv_uint32_t timestamp, const char *format, ...); + +static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) { + return m->timestamp; +} + +static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) { + m->timestamp = timestamp; +} + +static inline int msg_getNumElements(const HvMessage *m) { + return (int) m->numElements; +} + +/** Returns the number of bytes this message in memory. */ +static inline hv_size_t msg_getNumBytes(const HvMessage *m) { + return m->numBytes; +} + +static inline ElementType msg_getType(const HvMessage *m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + return (&(m->elem)+index)->type; +} + +static inline void msg_setBang(HvMessage *m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = BANG; + (&(m->elem)+index)->data.s = NULL; +} + +static inline bool msg_isBang(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == BANG) : false; +} + +static inline void msg_setFloat(HvMessage *m, int index, float f) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = FLOAT; + (&(m->elem)+index)->data.f = f; +} + +static inline float msg_getFloat(const HvMessage *const m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + return (&(m->elem)+index)->data.f; +} + +static inline bool msg_isFloat(const HvMessage *const m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == FLOAT) : false; +} + +static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = HASH; + (&(m->elem)+index)->data.h = h; +} + +static inline bool msg_isHash(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HASH) : false; +} + +/** Returns true if the element is a hash or symbol. False otherwise. */ +static inline bool msg_isHashLike(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HASH) || (msg_getType(m, index) == SYMBOL)) : false; +} + +/** Returns a 32-bit hash of the given string. */ +hv_uint32_t msg_symbolToHash(const char *s); + +/** Returns a 32-bit hash of the given element. */ +hv_uint32_t msg_getHash(const HvMessage *const m, int i); + +static inline void msg_setSymbol(HvMessage *m, int index, char *s) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = SYMBOL; + (&(m->elem)+index)->data.s = s; +} + +static inline char *msg_getSymbol(const HvMessage *m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + return (&(m->elem)+index)->data.s; +} + +static inline bool msg_isSymbol(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == SYMBOL) : false; +} + +bool msg_compareSymbol(const HvMessage *m, int i, const char *s); + +/** Returns 1 if the element i_m of message m is equal to element i_n of message n. */ +bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n); + +bool msg_hasFormat(const HvMessage *m, const char *fmt); + +/** + * Create a string representation of the message. Suitable for use by the print object. + * The resulting string must be freed by the caller. + */ +char *msg_toString(const HvMessage *msg); + +/** + * Resolves any number of dollar arguments and generates a string based on the arguments. + * @param m The message from which to take values + * @param n The message to fill in + * @param z The element index to resolve + * @param buf The scratch (i.e. resolution) buffer + * @param len The length of the scratch buffer + * @param args A string of 'i' and 's' chars indicating the type of the arguments, either indicies or strings + * @param varargs The components to resolve, either dollar indicies or strings. + * If the index is negative, the graph id is used + * @return true if the resolution buffer is needed, false otherwise. + */ +// bool msg_resolveDollarArguments(HvMessage *m, HvMessage *n, int z, char *buf, hv_size_t len, const char *args, ...); + +#endif // _HEAVY_MESSAGE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvTable.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvTable.h" + +hv_size_t hTable_init(HvTable *o, int length) { + o->length = length; + // true size of the table is always an integer multple of HV_N_SIMD + o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; + // add an extra length for mirroring + o->allocated = o->size + HV_N_SIMD; + o->head = 0; + hv_size_t numBytes = o->allocated * sizeof(float); + o->buffer = (float *) hv_malloc(numBytes); + hv_memset(o->buffer, numBytes); + return numBytes; +} + +hv_size_t hTable_initWithData(HvTable *o, int length, const float *const data) { + o->length = length; + o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; + o->allocated = o->size + HV_N_SIMD; + o->head = 0; + hv_size_t numBytes = o->size * sizeof(float); + o->buffer = (float *) hv_malloc(numBytes); + hv_memset(o->buffer, numBytes); + hv_memcpy(o->buffer, data, length*sizeof(float)); + return numBytes; +} + +hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) { + o->length = length; + o->size = length; + o->allocated = length; + o->buffer = data; + o->head = 0; + return 0; +} + +void hTable_free(HvTable *o) { + hv_free(o->buffer); +} + +int hTable_resize(HvTable *o, hv_uint32_t newLength) { + // TODO(mhroth): update context with memory allocated by table + // NOTE(mhroth): mirrored bytes are not necessarily carried over + const hv_uint32_t oldBytes = (hv_uint32_t) (o->size * sizeof(float)); + const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; + const hv_uint32_t newAllocated = newSize + HV_N_SIMD; + const hv_uint32_t newBytes = (hv_uint32_t) (newAllocated * sizeof(float)); + float *b = (float *) hv_realloc(o->buffer, newBytes); + hv_assert(b != NULL); // error while reallocing! + if (newSize > o->size) hv_clear_buffer(b+o->size, newAllocated-o->size); // clear new parts of the buffer + if (b != o->buffer) { + // the buffer has been reallocated, ensure that it is on a 32-byte boundary + if ((((uintptr_t) (const void *) b) & 0x10) == 0) { + o->buffer = b; + } else { + float *c = (float *) hv_malloc(newBytes); + hv_assert(c != NULL); + hv_clear_buffer(c, newLength); + const hv_size_t min = hv_min_ui(o->size, newLength); + hv_memcpy(c, b, min * sizeof(float)); + hv_free(b); + o->buffer = c; + } + } + o->length = newLength; + o->size = newSize; + o->allocated = newAllocated; + return (int) (newBytes - oldBytes); +} + +void hTable_onMessage(HvBase *_c, HvTable *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) { + hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space + + // send out the new size of the table + HvMessage *n = HV_MESSAGE_ON_STACK(1); + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o)); + sendMessage(_c, 0, n); + } + + else if (msg_compareSymbol(m,0,"mirror")) { + hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/HvTable.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_TABLE_H_ +#define _HEAVY_TABLE_H_ + +#include "HvBase.h" +#include "HvMessage.h" +#include "Utils.h" + +typedef struct HvTable { + float *buffer; + // the number of values that the table is requested to have + hv_uint32_t length; + + // the number of usable values that the table actually has + // this is always an even multiple of HV_N_SIMD + hv_uint32_t size; + + // Note that the true size of the table is (size + HV_N_SIMD), + // with the trailing values used by the system, e.g. to create a circular + // buffer + hv_uint32_t allocated; + + hv_uint32_t head; // the most recently written point +} HvTable; + +hv_size_t hTable_init(HvTable *o, int length); + +hv_size_t hTable_initWithData(HvTable *o, int length, const float *const data); + +hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data); + +void hTable_free(HvTable *o); + +int hTable_resize(HvTable *o, hv_uint32_t newLength); + +void hTable_onMessage(HvBase *_c, HvTable *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +static inline float *hTable_getBuffer(HvTable *o) { + return o->buffer; +} + +// the user-requested length of the table (number of floats) +static inline hv_uint32_t hTable_getLength(HvTable *o) { + return o->length; +} + +// the usable length of the table (an even multiple of HV_N_SIMD) +static inline hv_uint32_t hTable_getSize(HvTable *o) { + return o->size; +} + +// the number of floats allocated to this table (usually size + HV_N_SIMD) +static inline hv_uint32_t hTable_getAllocated(HvTable *o) { + return o->allocated; +} + +static inline hv_uint32_t hTable_getHead(HvTable *o) { + return o->head; +} + +static inline void hTable_setHead(HvTable *o, hv_uint32_t head) { + o->head = head; +} + +#endif // _HEAVY_TABLE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/MessagePool.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "MessagePool.h" +#include "HvMessage.h" +#include "Utils.h" + +// the number of bytes reserved at a time from the pool +#define MP_BLOCK_SIZE_BYTES 512 + +#if HV_APPLE +#pragma mark - MessageList +#endif + +typedef struct MessageListNode { + char *p; + struct MessageListNode *next; +} MessageListNode; + +static inline bool ml_hasAvailable(MessagePoolList *ml) { + return (ml->head != NULL); +} + +static char *ml_pop(MessagePoolList *ml) { + MessageListNode *n = ml->head; + ml->head = n->next; + n->next = ml->pool; + ml->pool = n; + char *const p = n->p; + n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer + return p; +} + +/** Push a MessageListNode with the given pointer onto the head of the queue. */ +static void ml_push(MessagePoolList *ml, void *p) { + MessageListNode *n = NULL; + if (ml->pool != NULL) { + // take an empty MessageListNode from the pool + n = ml->pool; + ml->pool = n->next; + } else { + // a MessageListNode is not available, allocate one + n = (MessageListNode *) hv_malloc(sizeof(MessageListNode)); + } + n->p = (char *) p; + n->next = ml->head; + ml->head = n; // push to the front of the queue +} + +static void ml_free(MessagePoolList *ml) { + if (ml != NULL) { + while (ml_hasAvailable(ml)) { + ml_pop(ml); + } + while (ml->pool != NULL) { + MessageListNode *n = ml->pool; + ml->pool = n->next; + hv_free(n); + } + } +} + +#if HV_APPLE +#pragma mark - MessagePool +#endif + +static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) { + return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0); +} + +hv_size_t mp_init(MessagePool *mp, hv_size_t numKB) { + mp->bufferSize = numKB * 1024; + mp->buffer = (char *) hv_malloc(mp->bufferSize); + mp->bufferIndex = 0; + + // initialise all message lists + for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) { + mp->lists[i].head = NULL; + mp->lists[i].pool = NULL; + } + + return mp->bufferSize; +} + +void mp_free(MessagePool *mp) { + hv_free(mp->buffer); + for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) { + ml_free(&mp->lists[i]); + } +} + +void mp_freeMessage(MessagePool *mp, HvMessage *m) { + const hv_size_t b = msg_getNumBytes(m); // the number of bytes that a message occupies in memory + const hv_size_t i = mp_messagelistIndexForSize(b); // the MessagePoolList index in the pool + MessagePoolList *ml = &mp->lists[i]; + const hv_size_t chunkSize = 32 << i; + hv_memset(m, chunkSize); // clear the chunk, just in case + ml_push(ml, m); +} + +HvMessage *mp_addMessage(MessagePool *mp, const HvMessage *m) { + const hv_size_t b = msg_getNumHeapBytes(m); + // determine the message list index to allocate data from based on the msg size + // smallest chunk size is 32 bytes + const hv_size_t i = mp_messagelistIndexForSize(b); + + assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment + MessagePoolList *ml = &mp->lists[i]; + const hv_size_t chunkSize = 32 << i; + + if (ml_hasAvailable(ml)) { + char *buf = ml_pop(ml); + msg_copyToBuffer(m, buf, chunkSize); + return (HvMessage *) buf; + } else { + // if no appropriately sized buffer is immediately available, increase the size of the used buffer + const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES; + hv_assert(newIndex <= mp->bufferSize); // have we have exceeded the buffer size? + + for (hv_size_t i = mp->bufferIndex; i < newIndex; i += chunkSize) { + ml_push(ml, mp->buffer + i); // push new nodes onto the list with chunk pointers + } + mp->bufferIndex = newIndex; + char *buf = ml_pop(ml); + msg_copyToBuffer(m, buf, chunkSize); + return (HvMessage *) buf; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/MessagePool.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MESSAGE_POOL_H_ +#define _MESSAGE_POOL_H_ + +#include "Utils.h" + +struct HvMessage; + +#define MP_NUM_MESSAGE_LISTS 4 + +typedef struct MessagePoolList { + struct MessageListNode *head; // list of currently available blocks + struct MessageListNode *pool; // list of currently used blocks +} MessagePoolList; + +typedef struct MessagePool { + char *buffer; // the buffer of all messages + hv_size_t bufferSize; // in bytes + hv_size_t bufferIndex; // the number of total reserved bytes + + MessagePoolList lists[MP_NUM_MESSAGE_LISTS]; +} MessagePool; + +/** + * The MessagePool is a basic memory management system. It reserves a large block of memory at initialisation + * and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are + * further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a MessagePoolList (MPL). + * An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes + * that point at each subblock (e.g. each 32-byte block of a 512-block chunk). + * + * MessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html + */ + +hv_size_t mp_init(struct MessagePool *mp, hv_size_t numKB); + +void mp_free(struct MessagePool *mp); + +/** + * Adds a message to the pool and returns a pointer to the copy. Returns NULL + * if no space was available in the pool. + */ +struct HvMessage *mp_addMessage(struct MessagePool *mp, const struct HvMessage *m); + +void mp_freeMessage(struct MessagePool *mp, struct HvMessage *m); + +#endif // _MESSAGE_POOL_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/MessageQueue.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "MessageQueue.h" +#include "Utils.h" + +hv_size_t mq_init(MessageQueue *q) { + q->head = NULL; + q->tail = NULL; + q->pool = NULL; + return mp_init(&q->mp, 1); +} + +void mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB) { + q->head = NULL; + q->tail = NULL; + q->pool = NULL; + mp_init(&q->mp, poolSizeKB); +} + +void mq_free(MessageQueue *q) { + mq_clear(q); + while (q->pool != NULL) { + MessageNode *n = q->pool; + q->pool = q->pool->next; + hv_free(n); + } + mp_free(&q->mp); +} + +static MessageNode *mq_getOrCreateNodeFromPool(MessageQueue *q) { + if (q->pool == NULL) { + // if necessary, create a new empty node + q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode)); + q->pool->next = NULL; + } + MessageNode *node = q->pool; + q->pool = q->pool->next; + return node; +} + +int mq_size(MessageQueue *q) { + int size = 0; + MessageNode *n = q->head; + while (n != NULL) { + ++size; + n = n->next; + } + return size; +} + +HvMessage *mq_addMessage(MessageQueue *q, const HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + MessageNode *node = mq_getOrCreateNodeFromPool(q); + node->m = mp_addMessage(&q->mp, m); + node->let = let; + node->sendMessage = sendMessage; + node->prev = NULL; + node->next = NULL; + + if (q->tail != NULL) { + // the list already contains elements + q->tail->next = node; + node->prev = q->tail; + q->tail = node; + } else { + // the list is empty + node->prev = NULL; + q->head = node; + q->tail = node; + } + return mq_node_getMessage(node); +} + +HvMessage *mq_addMessageByTimestamp(MessageQueue *q, HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + if (mq_hasMessage(q)) { + MessageNode *n = mq_getOrCreateNodeFromPool(q); + n->m = mp_addMessage(&q->mp, m); + n->let = let; + n->sendMessage = sendMessage; + + if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) { + // the message occurs before the current head + n->next = q->head; + q->head->prev = n; + n->prev = NULL; + q->head = n; + } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) { + // the message occurs after the current tail + n->next = NULL; + n->prev = q->tail; + q->tail->next = n; + q->tail = n; + } else { + // the message occurs somewhere between the head and tail + MessageNode *node = q->head; + while (node != NULL) { + if (m->timestamp < msg_getTimestamp(node->next->m)) { + MessageNode *r = node->next; + node->next = n; + n->next = r; + n->prev = node; + r->prev = n; + break; + } + node = node->next; + } + } + return n->m; + } else { + // add a message to the head + return mq_addMessage(q, m, let, sendMessage); + } +} + +void mq_pop(MessageQueue *q) { + if (mq_hasMessage(q)) { + MessageNode *n = q->head; + + mp_freeMessage(&q->mp, n->m); + n->m = NULL; + + n->let = 0; + n->sendMessage = NULL; + + q->head = n->next; + if (q->head == NULL) { + q->tail = NULL; + } else { + q->head->prev = NULL; + } + n->next = q->pool; + n->prev = NULL; + q->pool = n; + } +} + +void mq_removeMessage(MessageQueue *q, HvMessage *m, void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + if (mq_hasMessage(q)) { + if (mq_node_getMessage(q->head) == m) { // msg in head node + // only remove the message if sendMessage is the same as the stored one, + // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer + if (sendMessage == NULL || q->head->sendMessage == sendMessage) { + mq_pop(q); + } + } else { + MessageNode *prevNode = q->head; + MessageNode *currNode = q->head->next; + while ((currNode != NULL) && (currNode->m != m)) { + prevNode = currNode; + currNode = currNode->next; + } + if (currNode != NULL) { + if (sendMessage == NULL || currNode->sendMessage == sendMessage) { + mp_freeMessage(&q->mp, m); + currNode->m = NULL; + currNode->let = 0; + currNode->sendMessage = NULL; + if (currNode == q->tail) { // msg in tail node + prevNode->next = NULL; + q->tail = prevNode; + } else { // msg in middle node + prevNode->next = currNode->next; + currNode->next->prev = prevNode; + } + currNode->next = (q->pool == NULL) ? NULL : q->pool; + currNode->prev = NULL; + q->pool = currNode; + } + } + } + } +} + +void mq_clear(MessageQueue *q) { + while (mq_hasMessage(q)) { + mq_pop(q); + } +} + +void mq_clearAfter(MessageQueue *q, const double timestamp) { + MessageNode *n = q->tail; + while (n != NULL && timestamp <= msg_getTimestamp(n->m)) { + // free the node's message + mp_freeMessage(&q->mp, n->m); + n->m = NULL; + n->let = 0; + n->sendMessage = NULL; + + // the tail points at the previous node + q->tail = n->prev; + + // put the node back in the pool + n->next = q->pool; + n->prev = NULL; + if (q->pool != NULL) q->pool->prev = n; + q->pool = n; + + // update the tail node + n = q->tail; + } + + if (q->tail == NULL) q->head = NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/MessageQueue.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MESSAGE_QUEUE_H_ +#define _MESSAGE_QUEUE_H_ + +#include "HvMessage.h" +#include "MessagePool.h" + +struct HvBase; + +typedef struct MessageNode { + struct MessageNode *prev; // doubly linked list + struct MessageNode *next; + HvMessage *m; + void (*sendMessage)(struct HvBase *, int, const HvMessage *); + int let; +} MessageNode; + +/** A doubly linked list containing scheduled messages. */ +typedef struct MessageQueue { + MessageNode *head; // the head of the queue + MessageNode *tail; // the tail of the queue + MessageNode *pool; // the head of the reserve pool + MessagePool mp; +} MessageQueue; + +hv_size_t mq_init(MessageQueue *q); + +void mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB); + +void mq_free(MessageQueue *q); + +int mq_size(MessageQueue *q); + +static inline HvMessage *mq_node_getMessage(MessageNode *n) { + return n->m; +} + +static inline int mq_node_getLet(MessageNode *n) { + return n->let; +} + +static inline bool mq_hasMessage(MessageQueue *q) { + return (q->head != NULL); +} + +// true if there is a message and it occurs before (<) timestamp +static inline bool mq_hasMessageBefore(MessageQueue *const q, const hv_uint32_t timestamp) { + return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp); +} + +static inline MessageNode *mq_peek(MessageQueue *q) { + return q->head; +} + +/** Appends the message to the end of the queue. */ +HvMessage *mq_addMessage(MessageQueue *q, const HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)); + +/** Insert in ascending order the message acccording to its timestamp. */ +HvMessage *mq_addMessageByTimestamp(MessageQueue *q, HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)); + +/** Pop the message at the head of the queue (and free its memory). */ +void mq_pop(MessageQueue *q); + +/** Remove a message from the queue (and free its memory) */ +void mq_removeMessage(MessageQueue *q, HvMessage *m, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)); + +/** Clears (and frees) all messages in the queue. */ +void mq_clear(MessageQueue *q); + +/** Removes all messages occuring at or after the given timestamp. */ +void mq_clearAfter(MessageQueue *q, const double timestamp); + +#endif // _MESSAGE_QUEUE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalDel1.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalDel1.h" + +hv_size_t sDel1_init(SignalDel1 *o) { +#if HV_SIMD_AVX + o->x = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + o->x = _mm_setzero_ps(); +#elif HV_SIMD_NEON + o->x = vdupq_n_f32(0.0f); +#else + o->x = 0.0f; +#endif + return 0; +} + +void sDel1_onMessage(HvBase *_c, SignalDel1 *o, int letIn, const HvMessage *m) { + if (letIn == 2) { + if (msg_compareSymbol(m, 0, "clear")) { +#if HV_SIMD_AVX + o->x = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + o->x = _mm_setzero_ps(); +#elif HV_SIMD_NEON + o->x = vdupq_n_f32(0.0f); +#else + o->x = 0.0f; +#endif + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalDel1.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SIGNAL_DEL1_H_ +#define _SIGNAL_DEL1_H_ + +#include "HvBase.h" + +typedef struct SignalDel1 { + hv_bufferf_t x; +} SignalDel1; + +hv_size_t sDel1_init(SignalDel1 *o); + +void sDel1_onMessage(HvBase *_c, SignalDel1 *o, int letIn, const HvMessage *m); + +static inline void __hv_del1_f(SignalDel1 *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + __m256 x = _mm256_permute_ps(bIn0, _MM_SHUFFLE(2,1,0,3)); // [3 0 1 2 7 4 5 6] + __m256 n = _mm256_permute2f128_ps(o->x,x,0x1); // [h e f g 3 0 1 2] + *bOut = _mm256_blend_ps(x, n, 0x11); // [g 0 1 2 3 4 5 6] + o->x = x; +#elif HV_SIMD_SSE + __m128 n = _mm_blend_ps(o->x, bIn0, 0x7); + *bOut = _mm_shuffle_ps(n, n, _MM_SHUFFLE(2,1,0,3)); + o->x = bIn0; +#elif HV_SIMD_NEON + *bOut = vextq_f32(o->x, bIn0, 3); + o->x = bIn0; +#else + *bOut = o->x; + o->x = bIn0; +#endif +} + +#endif // _SIGNAL_DEL1_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalPhasor.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalPhasor.h" + +// input phase is in the range of [0,1]. It is independent of o->phase. +#if HV_SIMD_AVX +static void sPhasor_updatePhase(SignalPhasor *o, float p) { + o->phase = _mm256_set_ps( + p+1.0f+7.0f*o->step.f2sc, p+1.0f+6.0f*o->step.f2sc, + p+1.0f+5.0f*o->step.f2sc, p+1.0f+4.0f*o->step.f2sc, + p+1.0f+3.0f*o->step.f2sc, p+1.0f+2.0f*o->step.f2sc, + p+1.0f+o->step.f2sc, p+1.0f); + + // ensure that o->phase is still in range [1,2] + o->phase = _mm256_or_ps(_mm256_andnot_ps( + _mm256_set1_ps(-INFINITY), o->phase), _mm256_set1_ps(1.0f)); +#elif HV_SIMD_SSE +static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { + o->phase = _mm_set_epi32(3*o->step.s+p, 2*o->step.s+p, o->step.s+p, p); +#elif HV_SIMD_NEON +static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { + o->phase = (uint32x4_t) {p, o->step.s+p, 2*o->step.s+p, 3*o->step.s+p}; +#else // HV_SIMD_NONE +static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { + o->phase = p; +#endif +} + +static void sPhasor_updateFrequency(SignalPhasor *o, float f, double r) { +#if HV_SIMD_AVX + o->step.f2sc = (float) (f/r); + o->inc = _mm256_set1_ps((float) (8.0f*f/r)); + sPhasor_updatePhase(o, o->phase[0]); +#elif HV_SIMD_SSE + o->step.s = (hv_int32_t) (f*(4294967296.0/r)); + o->inc = _mm_set1_epi32(4*o->step.s); + sPhasor_updatePhase(o, (hv_uint32_t) (o->phase[0] & 0xFFFFFFFFL)); +#elif HV_SIMD_NEON + o->step.s = (hv_int32_t) (f*(4294967296.0/r)); + o->inc = vdupq_n_s32(4*o->step.s); + sPhasor_updatePhase(o, vgetq_lane_u32(o->phase, 0)); +#else // HV_SIMD_NONE + o->step.s = (hv_int32_t) (f*(4294967296.0/r)); + o->inc = o->step.s; + // no need to update phase +#endif +} + +hv_size_t sPhasor_init(SignalPhasor *o, double samplerate) { +#if HV_SIMD_AVX + o->phase = _mm256_set1_ps(1.0f); + o->inc = _mm256_setzero_ps(); + o->step.f2sc = (float) (1.0/samplerate); +#elif HV_SIMD_SSE + o->phase = _mm_setzero_si128(); + o->inc = _mm_setzero_si128(); + o->step.f2sc = (float) (4294967296.0/samplerate); +#elif HV_SIMD_NEON + o->phase = vdupq_n_u32(0); + o->inc = vdupq_n_s32(0); + o->step.f2sc = (float) (4294967296.0/samplerate); +#else // HV_SIMD_NONE + o->phase = 0; + o->inc = 0; + o->step.f2sc = (float) (4294967296.0/samplerate); +#endif + return 0; +} + +void sPhasor_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m) { + if (letIn == 1) { + if (msg_isFloat(m,0)) { + float phase = msg_getFloat(m,0); + while (phase < 0.0f) phase += 1.0f; // wrap phase to [0,1] + while (phase > 1.0f) phase -= 1.0f; +#if HV_SIMD_AVX + sPhasor_updatePhase(o, phase); +#else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE + sPhasor_updatePhase(o, (hv_int32_t) (phase * 4294967296.0)); +#endif + } + } +} + +hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate) { + sPhasor_updateFrequency(o, frequency, samplerate); + sPhasor_updatePhase(o, 0); + return 0; +} + +void sPhasor_k_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m) { + if (msg_isFloat(m,0)) { + switch (letIn) { + case 0: sPhasor_updateFrequency(o, msg_getFloat(m,0), ctx_getSampleRate(_c)); break; + case 1: { + float phase = msg_getFloat(m,0); + while (phase < 0.0f) phase += 1.0f; // wrap phase to [0,1] + while (phase > 1.0f) phase -= 1.0f; +#if HV_SIMD_AVX + sPhasor_updatePhase(o, phase); +#else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE + sPhasor_updatePhase(o, (hv_uint32_t) (phase * 4294967296.0)); +#endif + break; + } + default: break; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalPhasor.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_SIGNAL_PHASOR_H_ +#define _HEAVY_SIGNAL_PHASOR_H_ + +#include "HvBase.h" + +typedef struct SignalPhasor { +#if HV_SIMD_AVX + __m256 phase; // current phase + __m256 inc; // phase increment +#elif HV_SIMD_SSE + __m128i phase; + __m128i inc; +#elif HV_SIMD_NEON + uint32x4_t phase; + int32x4_t inc; +#else // HV_SIMD_NONE + hv_uint32_t phase; + hv_int32_t inc; +#endif + union { + float f2sc; // float to step conversion (used for __phasor~f) + hv_int32_t s; // step value (used for __phasor_k~f) + } step; +} SignalPhasor; + +hv_size_t sPhasor_init(SignalPhasor *o, double samplerate); + +hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate); + +void sPhasor_k_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m); + +void sPhasor_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m); + +static inline void __hv_phasor_f(SignalPhasor *o, hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + __m256 p = _mm256_mul_ps(bIn, _mm256_set1_ps(o->step.f2sc)); // a b c d e f g h + + __m256 z = _mm256_setzero_ps(); + + // http://stackoverflow.com/questions/11906814/how-to-rotate-an-sse-avx-vector + __m256 a = _mm256_permute_ps(p, _MM_SHUFFLE(2,1,0,3)); // d a b c h e f g + __m256 b = _mm256_permute2f128_ps(a, a, 0x01); // h e f g d a b c + __m256 c = _mm256_blend_ps(a, b, 0x10); // d a b c d e f g + __m256 d = _mm256_blend_ps(c, z, 0x01); // 0 a b c d e f g + __m256 e = _mm256_add_ps(p, d); // a (a+b) (b+c) (c+d) (d+e) (e+f) (f+g) (g+h) + + __m256 f = _mm256_permute_ps(e, _MM_SHUFFLE(1,0,3,2)); // (b+c) (c+d) a (a+b) (f+g) (g+h) (d+e) (e+f) + __m256 g = _mm256_permute2f128_ps(f, f, 0x01); // (f+g) (g+h) (d+e) (e+f) (b+c) (c+d) a (a+b) + __m256 h = _mm256_blend_ps(f, g, 0x33); // (b+c) (c+d) a (a+b) (b+c) (c+d) (d+e) (e+f) + __m256 i = _mm256_blend_ps(h, z, 0x03); // 0 0 a (a+b) (b+c) (c+d) (d+e) (e+f) + __m256 j = _mm256_add_ps(e, i); // a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) (c+d+e+f) (d+e+f+g) (e+f+g+h) + + __m256 k = _mm256_permute2f128_ps(j, z, 0x02); // 0 0 0 0 a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) + __m256 m = _mm256_add_ps(j, k); // a (a+b) (a+b+c) (a+b+c+d) (a+b+c+d+e) (a+b+c+d+e+f) (a+b+c+d+e+f+g) (a+b+c+d+e+f+g+h) + + __m256 n = _mm256_or_ps(_mm256_andnot_ps( + _mm256_set1_ps(-INFINITY), + _mm256_add_ps(o->phase, m)), + _mm256_set1_ps(1.0f)); + + *bOut = _mm256_sub_ps(n, _mm256_set1_ps(1.0f)); + + __m256 x = _mm256_permute_ps(n, _MM_SHUFFLE(3,3,3,3)); + o->phase = _mm256_permute2f128_ps(x, x, 0x11); +#elif HV_SIMD_SSE + __m128i p = _mm_cvtps_epi32(_mm_mul_ps(bIn, _mm_set1_ps(o->step.f2sc))); // convert frequency to step + p = _mm_add_epi32(p, _mm_slli_si128(p, 4)); // add incremental steps to phase (prefix sum) + p = _mm_add_epi32(p, _mm_slli_si128(p, 8)); // http://stackoverflow.com/questions/10587598/simd-prefix-sum-on-intel-cpu?rq=1 + p = _mm_add_epi32(o->phase, p); + *bOut = _mm_sub_ps(_mm_castsi128_ps( + _mm_or_si128(_mm_srli_epi32(p, 9), + (__m128i) {0x3F8000003F800000L, 0x3F8000003F800000L})), + _mm_set1_ps(1.0f)); + o->phase = _mm_shuffle_epi32(p, _MM_SHUFFLE(3,3,3,3)); +#elif HV_SIMD_NEON + int32x4_t p = vcvtq_s32_f32(vmulq_n_f32(bIn, o->step.f2sc)); + p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 3)); // http://stackoverflow.com/questions/11259596/arm-neon-intrinsics-rotation + p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 2)); + uint32x4_t pp = vaddq_u32(o->phase, vreinterpretq_u32_s32(p)); + *bOut = vsubq_f32(vreinterpretq_f32_u32(vorrq_u32(vshrq_n_u32(pp, 9), vdupq_n_u32(0x3F800000))), vdupq_n_f32(1.0f)); + o->phase = vdupq_n_u32(pp[3]); +#else // HV_SIMD_NONE + const hv_uint32_t p = (o->phase >> 9) | 0x3F800000; + *bOut = *((float *) (&p)) - 1.0f; + o->phase += ((int) (bIn * o->step.f2sc)); +#endif +} + +static inline void __hv_phasor_k_f(SignalPhasor *o, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_sub_ps(o->phase, _mm256_set1_ps(1.0f)); + o->phase = _mm256_or_ps(_mm256_andnot_ps( + _mm256_set1_ps(-INFINITY), + _mm256_add_ps(o->phase, o->inc)), + _mm256_set1_ps(1.0f)); +#elif HV_SIMD_SSE + *bOut = _mm_sub_ps(_mm_castsi128_ps( + _mm_or_si128(_mm_srli_epi32(o->phase, 9), + (__m128i) {0x3F8000003F800000L, 0x3F8000003F800000L})), + _mm_set1_ps(1.0f)); + o->phase = _mm_add_epi32(o->phase, o->inc); +#elif HV_SIMD_NEON + *bOut = vsubq_f32(vreinterpretq_f32_u32( + vorrq_u32(vshrq_n_u32(o->phase, 9), + vdupq_n_u32(0x3F800000))), + vdupq_n_f32(1.0f)); + o->phase = vaddq_u32(o->phase, vreinterpretq_u32_s32(o->inc)); +#else // HV_SIMD_NONE + const hv_uint32_t p = (o->phase >> 9) | 0x3F800000; + *bOut = *((float *) (&p)) - 1.0f; + o->phase += o->inc; +#endif +} + +#endif // _HEAVY_SIGNAL_PHASOR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalRPole.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalRPole.h" + +hv_size_t sRPole_init(SignalRPole *o) { +#if HV_SIMD_AVX + sDel1_init(&o->sDel1_fxiLN); + sDel1_init(&o->sDel1_kjkpV); + sDel1_init(&o->sDel1_dkIWc); + sDel1_init(&o->sDel1_bVeoW); + sDel1_init(&o->sDel1_PulZn); + sDel1_init(&o->sDel1_yTFig); + sDel1_init(&o->sDel1_Is9Qf); + sDel1_init(&o->sDel1_LIyNt); + sDel1_init(&o->sDel1_VqpU3); + sDel1_init(&o->sDel1_ZVYeg); + sDel1_init(&o->sDel1_IVAZh); + sDel1_init(&o->sDel1_F8WrY); + sDel1_init(&o->sDel1_rkFMy); + sDel1_init(&o->sDel1_BeqSK); + __hv_zero_f(&o->ym); +#elif HV_SIMD_SSE || HV_SIMD_NEON + sDel1_init(&o->sDel1_i8Twk); + sDel1_init(&o->sDel1_KYibU); + sDel1_init(&o->sDel1_spa5V); + sDel1_init(&o->sDel1_3HXdb); + sDel1_init(&o->sDel1_Aj1oK); + sDel1_init(&o->sDel1_jNX1g); + __hv_zero_f(&o->ym); +#else + o->ym = 0.0f; +#endif + return 0; +} + +void sRPole_onMessage(HvBase *_c, SignalRPole *o, int letIn, const HvMessage *m) { + // TODO +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalRPole.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SIGNAL_RPOLE_H_ +#define _SIGNAL_RPOLE_H_ + +#include "HvBase.h" +#include "SignalDel1.h" +#include "HeavyMath.h" + +// implements y[n] = x[n] - a*y[n-1] +// H(z) = 1/(1+a*z^-1) +typedef struct SignalRPole { +#if HV_SIMD_AVX + SignalDel1 sDel1_fxiLN; + SignalDel1 sDel1_kjkpV; + SignalDel1 sDel1_dkIWc; + SignalDel1 sDel1_bVeoW; + SignalDel1 sDel1_PulZn; + SignalDel1 sDel1_yTFig; + SignalDel1 sDel1_Is9Qf; + SignalDel1 sDel1_LIyNt; + SignalDel1 sDel1_VqpU3; + SignalDel1 sDel1_ZVYeg; + SignalDel1 sDel1_IVAZh; + SignalDel1 sDel1_F8WrY; + SignalDel1 sDel1_rkFMy; + SignalDel1 sDel1_BeqSK; + hv_bufferf_t ym; +#elif HV_SIMD_SSE || HV_SIMD_NEON + SignalDel1 sDel1_i8Twk; + SignalDel1 sDel1_KYibU; + SignalDel1 sDel1_spa5V; + SignalDel1 sDel1_3HXdb; + SignalDel1 sDel1_Aj1oK; + SignalDel1 sDel1_jNX1g; + hv_bufferf_t ym; +#else + hv_bufferf_t ym; +#endif +} SignalRPole; + +hv_size_t sRPole_init(SignalRPole *o); + +void sRPole_onMessage(HvBase *_c, SignalRPole *o, int letIn, const HvMessage *m); + +static inline void __hv_rpole_f(SignalRPole *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + hv_bufferf_t a, b, c, d, e, f, g, i, j, k, l, m, n; + __hv_del1_f(&o->sDel1_fxiLN, bIn1, &a); + __hv_mul_f(bIn1, a, &b); + __hv_del1_f(&o->sDel1_kjkpV, a, &a); + __hv_mul_f(b, a, &c); + __hv_del1_f(&o->sDel1_dkIWc, a, &a); + __hv_mul_f(c, a, &d); + __hv_del1_f(&o->sDel1_bVeoW, a, &a); + __hv_mul_f(d, a, &e); + __hv_del1_f(&o->sDel1_PulZn, a, &a); + __hv_mul_f(e, a, &f); + __hv_del1_f(&o->sDel1_yTFig, a, &a); + __hv_mul_f(f, a, &g); + __hv_del1_f(&o->sDel1_Is9Qf, a, &a); + __hv_mul_f(g, a, &a); + __hv_del1_f(&o->sDel1_LIyNt, bIn0, &i); + __hv_del1_f(&o->sDel1_VqpU3, i, &j); + __hv_del1_f(&o->sDel1_ZVYeg, j, &k); + __hv_del1_f(&o->sDel1_IVAZh, k, &l); + __hv_del1_f(&o->sDel1_F8WrY, l, &m); + __hv_del1_f(&o->sDel1_rkFMy, m, &n); + __hv_mul_f(i, bIn1, &i); + __hv_sub_f(bIn0, i, &i); + __hv_fma_f(j, b, i, &i); + __hv_mul_f(k, c, &c); + __hv_sub_f(i, c, &c); + __hv_fma_f(l, d, c, &c); + __hv_mul_f(m, e, &e); + __hv_sub_f(c, e, &e); + __hv_fma_f(n, f, e, &e); + __hv_del1_f(&o->sDel1_BeqSK, n, &n); + __hv_mul_f(n, g, &g); + __hv_sub_f(e, g, &g); + __hv_fma_f(a, o->ym, g, &g); + o->ym = g; + *bOut = g; +#elif HV_SIMD_SSE || HV_SIMD_NEON + hv_bufferf_t a, b, c, e, f; + __hv_del1_f(&o->sDel1_i8Twk, bIn1, &a); + __hv_mul_f(bIn1, a, &b); + __hv_del1_f(&o->sDel1_KYibU, a, &a); + __hv_mul_f(b, a, &c); + __hv_del1_f(&o->sDel1_spa5V, a, &a); + __hv_mul_f(c, a, &a); + __hv_del1_f(&o->sDel1_3HXdb, bIn0, &e); + __hv_del1_f(&o->sDel1_Aj1oK, e, &f); + __hv_mul_f(e, bIn1, &e); + __hv_sub_f(bIn0, e, &e); + __hv_fma_f(f, b, e, &e); + __hv_del1_f(&o->sDel1_jNX1g, f, &f); + __hv_mul_f(f, c, &c); + __hv_sub_f(e, c, &c); + __hv_fma_f(a, o->ym, c, &c); + o->ym = c; + *bOut = c; +#else + *bOut = bIn0 - bIn1 * o->ym; + o->ym = *bOut; +#endif +} + +#endif // _SIGNAL_RPOLE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalSamphold.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalSamphold.h" + +hv_size_t sSamphold_init(SignalSamphold *o) { +#if HV_SIMD_AVX + o->s = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + o->s = _mm_setzero_ps(); +#elif HV_SIMD_NEON + o->s = vdupq_n_f32(0.0f); +#else + o->s = 0.0f; +#endif + return 0; +} + +void sSamphold_onMessage(HvBase *_c, SignalSamphold *o, int letIndex, + const HvMessage *const m, void *sendMessage) { + switch (letIndex) { + case 2: { + if (msg_isFloat(m,0)) { +#if HV_SIMD_AVX + o->s = _mm256_set1_ps(msg_getFloat(m,0)); +#elif HV_SIMD_SSE + o->s = _mm_set1_ps(msg_getFloat(m,0)); +#elif HV_SIMD_NEON + o->s = vdupq_n_f32(msg_getFloat(m,0)); +#else + o->s = msg_getFloat(m,0); +#endif + } + break; + } + default: break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalSamphold.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,248 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SIGNAL_SAMPHOLD_H_ +#define _SIGNAL_SAMPHOLD_H_ + +#include "HvBase.h" + +typedef struct SignalSamphold { + hv_bufferf_t s; +} SignalSamphold; + +hv_size_t sSamphold_init(SignalSamphold *o); + +static inline void __hv_samphold_f(SignalSamphold *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_samphold_f() not implemented +#elif HV_SIMD_SSE + switch (_mm_movemask_ps(bIn1)) { + default: + case 0x0: *bOut = o->s; break; + case 0x1: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(0,0,0,0)); + o->s = *bOut; + break; + } + case 0x2: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(1,1,1,1)); + *bOut = _mm_blend_ps(o->s, x, 0xE); + o->s = x; + break; + } + case 0x3: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(1,1,1,1)); + *bOut = _mm_blend_ps(bIn0, x, 0xC); + o->s = x; + break; + } + case 0x4: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + *bOut = _mm_blend_ps(o->s, x, 0xC); + o->s = x; + break; + } + case 0x5: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,0,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + break; + } + case 0x6: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,1,0)); + *bOut = _mm_blend_ps(o->s, x, 0xE); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + break; + } + case 0x7: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + *bOut = _mm_blend_ps(bIn0, x, 0x8); + o->s = x; + break; + } + case 0x8: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + *bOut = _mm_blend_ps(o->s, x, 0x8); + o->s = x; + break; + } + case 0x9: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,0,0,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xA: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,1,1,0)); + *bOut = _mm_blend_ps(o->s, x, 0xE); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xB: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,1,1,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xC: { + *bOut = _mm_blend_ps(o->s, bIn0, 0xC); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xD: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,2,0,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xE: { + *bOut = _mm_blend_ps(o->s, bIn0, 0xE); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xF: { + *bOut = bIn0; + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + } +#elif HV_SIMD_NEON + uint32x4_t mmA = vandq_u32( + vreinterpretq_u32_f32(bIn1), (uint32x4_t) {0x1, 0x2, 0x4, 0x8}); // [0 1 2 3] + uint32x4_t mmB = vextq_u32(mmA, mmA, 2); // [2 3 0 1] + uint32x4_t mmC = vorrq_u32(mmA, mmB); // [0+2 1+3 0+2 1+3] + uint32x4_t mmD = vextq_u32(mmC, mmC, 3); // [1+3 0+2 1+3 0+2] + uint32x4_t mmE = vorrq_u32(mmC, mmD); // [0+1+2+3 ...] + uint32_t movemask = vgetq_lane_u32(mmE, 0); + switch (movemask) { + default: + case 0x0: *bOut = o->s; break; + case 0x1: { + *bOut = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + o->s = *bOut; + break; + } + case 0x2: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + *bOut = vextq_f32(o->s, x, 3); + o->s = x; + break; + } + case 0x3: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, ~0x0, ~0x0, ~0x0}))); + o->s = x; + break; + } + case 0x4: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); + *bOut = vextq_f32(o->s, x, 2); + o->s = x; + break; + } + case 0x5: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {~0x0, ~0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, ~0x0, ~0x0}))); + o->s = y; + } + case 0x6: { + const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + float32x4_t z = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, ~0x0, ~0x0, 0x0}))); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(z), (uint32x4_t) {~0x0, ~0x0, ~0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0x0, ~0x0}))); + o->s = y; + } + case 0x7: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, ~0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0x0, ~0x0, ~0x0}))); + o->s = x; + break; + } + case 0x8: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + *bOut = vextq_f32(o->s, x, 1); + o->s = x; + break; + } + case 0x9: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {~0x0, ~0x0, ~0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0x0, 0x0, ~0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + } + case 0xA: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + float32x4_t z = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, ~0x0, ~0x0, 0x0}))); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(z), (uint32x4_t) {~0x0, ~0x0, ~0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0x0, ~0x0}))); + o->s = y; + } + case 0xB: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, ~0x0, 0x0, ~0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0x0, ~0x0, 0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + case 0xC: { + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, ~0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0x0, ~0x0, ~0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + case 0xD: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, 0x0, ~0x0, ~0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, ~0x0, 0x0, 0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + } + case 0xE: { + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, ~0x0, ~0x0, ~0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + case 0xF: { + *bOut = bIn0; + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + } +#else // HV_SIMD_NONE + if (bIn1 != 0.0f) o->s = bIn0; + *bOut = o->s; +#endif +} + +void sSamphold_onMessage(HvBase *_c, SignalSamphold *o, int letIndex, + const HvMessage *const m, void *sendMessage); + +#endif // _SIGNAL_SAMPHOLD_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalVar.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalVar.h" + +// __var~f + +static void sVarf_update(SignalVarf *o, float k, float step, bool reverse) { +#if HV_SIMD_AVX + if (reverse) o->v = _mm256_setr_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k); + else o->v = _mm256_set_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k); +#elif HV_SIMD_SSE + if (reverse) o->v = _mm_setr_ps(k+3.0f*step, k+2.0f*step, k+step, k); + else o->v = _mm_set_ps(k+3.0f*step, k+2.0f*step, k+step, k); +#elif HV_SIMD_NEON + if (reverse) o->v = (float32x4_t) {3.0f*step+k, 2.0f*step+k, step+k, k}; + else o->v = (float32x4_t) {k, step+k, 2.0f*step+k, 3.0f*step+k}; +#else // HV_SIMD_NONE + o->v = k; +#endif +} + +hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse) { + sVarf_update(o, k, step, reverse); + return 0; +} + +void sVarf_onMessage(HvBase *_c, SignalVarf *o, const HvMessage *m) { + if (msg_isFloat(m,0)) { + sVarf_update(o, msg_getFloat(m,0), msg_isFloat(m,1) ? msg_getFloat(m,1) : 0.0f, msg_getNumElements(m) == 3); + } +} + + + +// __var~i + +static void sVari_update(SignalVari *o, int k, int step, bool reverse) { +#if HV_SIMD_AVX + if (reverse) o->v = _mm256_setr_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k); + else o->v = _mm256_set_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k); +#elif HV_SIMD_SSE + if (reverse) o->v = _mm_setr_epi32(k+3*step, k+2*step, k+step, k); + else o->v = _mm_set_epi32(k+3*step, k+2*step, k+step, k); +#elif HV_SIMD_NEON + if (reverse) o->v = (int32x4_t) {3*step+k, 2*step+k, step+k, k}; + else o->v = (int32x4_t) {k, step+k, 2*step+k, 3*step+k}; +#else // HV_SIMD_NEON + o->v = k; +#endif +} + +hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse) { + sVari_update(o, k, step, reverse); + return 0; +} + +void sVari_onMessage(HvBase *_c, SignalVari *o, const HvMessage *m) { + if (msg_isFloat(m,0)) { + sVari_update(o, (int) msg_getFloat(m,0), msg_isFloat(m,1) ? (int) msg_getFloat(m,1) : 0, msg_getNumElements(m) == 3); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/SignalVar.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_SIGNAL_VAR_H_ +#define _HEAVY_SIGNAL_VAR_H_ + +#include "HvBase.h" + +// __var~f +// __varset~f + +typedef struct SignalVarf { + hv_bufferf_t v; +} SignalVarf; + +hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse); + +static inline void __hv_var_f(SignalVarf *o, hv_bOutf_t bOut) { + *bOut = o->v; +} + +static inline void sVarsetf_process(SignalVarf *o, hv_bInf_t bIn) { + o->v = bIn; +} + +void sVarf_onMessage(HvBase *_c, SignalVarf *o, const HvMessage *m); + + + +// __var~i +// __varset~i + +typedef struct SignalVari { + hv_bufferi_t v; +} SignalVari; + +hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse); + +static inline void __hv_var_i(SignalVari *o, hv_bOuti_t bOut) { + *bOut = o->v; +} + +#if HV_SIMD_AVX +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256i)(__v8si) {_a,_b,_c,_d,_e,_f,_g,_h}) +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256i)(__v8si) {_h,_g,_f,_e,_d,_c,_b,_a}) +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256) {_a,_b,_c,_d,_e,_f,_g,_h}) +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256) {_h,_g,_f,_e,_d,_c,_b,_a}) +#elif HV_SIMD_SSE +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128i)(__v4si) {_a,_b,_c,_d}) +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128i)(__v4si) {_d,_c,_b,_a}) +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128) {_a,_b,_c,_d}) +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128) {_d,_c,_b,_a}) +#elif HV_SIMD_NEON +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_a,_b,_c,_d}) +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_d,_c,_b,_a}) +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_a,_b,_c,_d}) +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_d,_c,_b,_a}) +#else // HV_SIMD_NONE +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#endif +// r == 0: forwards, r == 1: backwards +#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h,_r) __hv_var_k_i_##_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) +#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h,_r) __hv_var_k_f_##_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) + +static inline void sVarseti_process(SignalVari *o, hv_bIni_t bIn) { + o->v = bIn; +} + +void sVari_onMessage(HvBase *_c, SignalVari *o, const HvMessage *m); + +#endif // _HEAVY_SIGNAL_VAR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_H_ +#define _HEAVY_UTILS_H_ + +// Type definitions +#if _WIN32 || _WIN64 || WINAPI_FAMILY +#define HV_WIN 1 +#include <stddef.h> +#if defined (_MSC_VER) +#define HV_MSVC 1 +#endif +#define hv_size_t unsigned long +#define hv_uint32_t unsigned int +#define hv_uint16_t unsigned short +#define hv_int32_t int +#elif __APPLE__ && __MACH__ +#define HV_APPLE 1 +#include <stddef.h> +#define hv_size_t size_t +#define hv_uint32_t unsigned int +#define hv_uint16_t unsigned short +#define hv_int32_t int +#elif __unix__ || __unix +#define HV_UNIX 1 +#include <stddef.h> +#include <stdint.h> +#define hv_size_t size_t +#define hv_uint32_t uint32_t +#define hv_uint16_t uint16_t +#define hv_int32_t int32_t +#else +#error Unsupported platform +#endif + +// Memory management +extern void *hv_alloca(hv_size_t numbytes); +extern void *hv_malloc(hv_size_t numbytes); // allocates memory on 16 byte boundaries and clears it to zero +extern void hv_free(void *ptr); // frees aligned memory +extern void *hv_realloc(void *ptr, hv_size_t numBytes); +extern void *hv_memcpy(void *dest, const void *src, hv_size_t numbytes); +extern void *hv_memset(void *ptr, hv_size_t numbytes); // sets everything to 0 + +// String handling +extern hv_size_t hv_strlen(const char *str); +extern char *hv_strncat(char *dest, const char *str, hv_size_t n); +extern char *hv_strncpy(char *dest, const char *str, hv_size_t n); +extern int hv_strcmp(const char *str1, const char *str2); +extern int hv_strncmp(const char *str1, const char *str2, hv_size_t n); +extern int hv_snprintf(char *dest, hv_size_t n, const char *format, ...); + +// Math +extern int hv_max_i(int x, int y); +extern hv_size_t hv_max_ui(hv_size_t x, hv_size_t y); +extern int hv_min_i(int x, int y); +extern hv_size_t hv_min_ui(hv_size_t x, hv_size_t y); +extern float hv_max_f(float x, float y); +extern float hv_min_f(float x, float y); +extern double hv_max_d(double x, double y); +extern double hv_min_d(double x, double y); +extern float hv_sin_f(float x); +extern float hv_sinh_f(float x); +extern float hv_cos_f(float x); +extern float hv_cosh_f(float x); +extern float hv_tan_f(float x); +extern float hv_tanh_f(float x); +extern float hv_asin_f(float x); +extern float hv_asinh_f(float x); +extern float hv_acos_f(float x); +extern float hv_acosh_f(float x); +extern float hv_atan_f(float x); +extern float hv_atanh_f(float x); +extern float hv_atan2_f(float x, float y); +extern float hv_exp_f(float x); +extern float hv_abs_f(float x); +extern float hv_sqrt_f(float x); +extern float hv_log_f(float x); +extern float hv_log2_f(float x); +extern float hv_log10_f(float x); +extern float hv_ceil_f(float x); +extern float hv_floor_f(float x); +extern float hv_round_f(float x); +extern float hv_pow_f(float x, float y); +extern float hv_fma_f(float x, float y, float z); + +// Utilities +extern void hv_assert(int e); +extern void hv_clear_buffer(float *b, int n); +extern hv_uint32_t hv_min_max_log2(hv_uint32_t x); + +// SIMD +#ifndef HV_SIMD_NONE + #define HV_SIMD_NEON __ARM_NEON__ + #define HV_SIMD_SSE (__SSE__ && __SSE2__ && __SSE3__ && __SSSE3__ && __SSE4_1__) + #define HV_SIMD_AVX (__AVX__ && HV_SIMD_SSE) // it is required that if AVX exists then SSE will also be available + #define HV_SIMD_FMA __FMA__ +#endif + +#ifdef HV_WIN +#include "Utils_windows.h" +#elif HV_APPLE +#include "Utils_mac.h" +#elif HV_UNIX +#include "Utils_unix.h" +#else +#error Unsupported platform +#endif + +#if HV_SIMD_NEON // NEON + #define HV_N_SIMD 4 + #define hv_bufferf_t float32x4_t + #define hv_bufferi_t int32x4_t + #define hv_bInf_t float32x4_t + #define hv_bOutf_t float32x4_t* + #define hv_bIni_t int32x4_t + #define hv_bOuti_t int32x4_t* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#elif HV_SIMD_AVX // AVX + #define HV_N_SIMD 8 + #define hv_bufferf_t __m256 + #define hv_bufferi_t __m256i + #define hv_bInf_t __m256 + #define hv_bOutf_t __m256* + #define hv_bIni_t __m256i + #define hv_bOuti_t __m256i* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#elif HV_SIMD_SSE // SSE + #define HV_N_SIMD 4 + #define hv_bufferf_t __m128 + #define hv_bufferi_t __m128i + #define hv_bInf_t __m128 + #define hv_bOutf_t __m128* + #define hv_bIni_t __m128i + #define hv_bOuti_t __m128i* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#else // DEFAULT + #define HV_N_SIMD 1 + #undef HV_SIMD_NONE + #define HV_SIMD_NONE 1 + #define hv_bufferf_t float + #define hv_bufferi_t int + #define hv_bInf_t float + #define hv_bOutf_t float* + #define hv_bIni_t int + #define hv_bOuti_t int* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#endif + +#define HV_N_SIMD_MASK (HV_N_SIMD-1) + +#endif // _HEAVY_UTILS_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils_mac.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Utils_mac.h" + +#if HV_APPLE + +hv_size_t hv_max_ui(hv_size_t x, hv_size_t y) { + return (x >= y) ? x : y; +} + +hv_size_t hv_min_ui(hv_size_t x, hv_size_t y) { + return (x <= y) ? x : y; +} + +int hv_max_i(int x, int y) { + return (x >= y) ? x : y; +} + +int hv_min_i(int x, int y) { + return (x <= y) ? x : y; +} + +hv_uint32_t hv_min_max_log2(hv_uint32_t x) { + // finds ceil(log2(x)) + // http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + return (hv_uint32_t) ((8 * sizeof(unsigned int)) - __builtin_clz(x - 1)); +} + +#endif // HV_APPLE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils_mac.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_MAC_H_ +#define _HEAVY_UTILS_MAC_H_ + +#include "Utils.h" + +#if HV_APPLE +#include <alloca.h> +#if HV_SIMD_AVX || HV_SIMD_SSE +#include <immintrin.h> +#include <mm_malloc.h> +#elif HV_SIMD_NEON +#include <arm_neon.h> +#endif +#include <assert.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HV_EXPORT +#define HV_FORCE_INLINE inline __attribute__((always_inline)) + +// Memory management +#define hv_alloca(_n) alloca(_n) +#if HV_SIMD_AVX || HV_SIMD_SSE + #define hv_malloc(_n) _mm_malloc(_n, 32) // 32 to ensure AVX compatability (16 otherwise) + #define hv_free(x) _mm_free(x) +#else + #define hv_malloc(_n) malloc(_n) + #define hv_free(x) free(x) +#endif +#define hv_realloc(a, b) realloc(a, b) +#define hv_memcpy(a, b, c) memcpy(a, b, c) +#define hv_memset(a, b) memset(a, 0, b) + +// Strings +#define hv_strlen(a) strlen(a) +#define hv_strncat(a, b, c) strncat(a, b, c) +#define hv_strncpy(a, b, c) strncpy(a, b, c) +#define hv_strcmp(a, b) strcmp(a, b) +#define hv_strncmp(a, b, c) strncmp(a, b, c) +#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) + +// Math +#define hv_max_f(a, b) fmaxf(a, b) +#define hv_min_f(a, b) fminf(a, b) +#define hv_max_d(a, b) fmax(a, b) +#define hv_min_d(a, b) fmin(a, b) +#define hv_sin_f(a) sinf(a) +#define hv_sinh_f(a) sinhf(a) +#define hv_cos_f(a) cosf(a) +#define hv_cosh_f(a) coshf(a) +#define hv_tan_f(a) tanf(a) +#define hv_tanh_f(a) tanhf(a) +#define hv_asin_f(a) asinf(a) +#define hv_asinh_f(a) asinhf(a) +#define hv_acos_f(a) acosf(a) +#define hv_acosh_f(a) acoshf(a) +#define hv_atan_f(a) atanf(a) +#define hv_atanh_f(a) atanhf(a) +#define hv_atan2_f(a, b) atan2f(a, b) +#define hv_exp_f(a) expf(a) +#define hv_abs_f(a) fabsf(a) +#define hv_sqrt_f(a) sqrtf(a) +#define hv_log_f(a) logf(a) +#define hv_log2_f(a) log2f(a) +#define hv_log10_f(a) log10f(a) +#define hv_ceil_f(a) ceilf(a) +#define hv_floor_f(a) floorf(a) +#define hv_round_f(a) roundf(a) +#define hv_pow_f(a, b) powf(a, b) +#define hv_fma_f(a, b, c) ((a*b)+c) // TODO(joe): use 'fmaf(a, b, c)' once emscripten supports it + +// Utilities +#define hv_assert(e) assert(e) +#define hv_clear_buffer(b, n) memset(b, 0, (n)*sizeof(float)) + +#endif // HV_APPLE +#endif // _HEAVY_UTILS_MAC_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils_unix.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Utils_unix.h" + +#if HV_UNIX + +hv_size_t hv_max_ui(hv_size_t x, hv_size_t y) { + return (x >= y) ? x : y; +} + +hv_size_t hv_min_ui(hv_size_t x, hv_size_t y) { + return (x <= y) ? x : y; +} + +int hv_max_i(int x, int y) { + return (x >= y) ? x : y; +} + +int hv_min_i(int x, int y) { + return (x <= y) ? x : y; +} + +hv_uint32_t hv_min_max_log2(hv_uint32_t x) { + // finds ceil(log2(x)) + // http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + return (hv_uint32_t) ((8 * sizeof(unsigned int)) - __builtin_clz(x - 1)); +} + +#endif // HV_UNIX
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils_unix.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_UNIX_H_ +#define _HEAVY_UTILS_UNIX_H_ + +#include "Utils.h" + +#if HV_UNIX +#if HV_SIMD_AVX || HV_SIMD_SSE +#include <immintrin.h> +#include <mm_malloc.h> +#elif HV_SIMD_NEON +#include <arm_neon.h> +#endif +#include <alloca.h> +#include <assert.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HV_EXPORT +#define HV_FORCE_INLINE inline __attribute__((always_inline)) + +// Memory management +#define hv_alloca(_n) alloca(_n) +#if HV_SIMD_AVX || HV_SIMD_SSE + #define hv_malloc(_n) _mm_malloc(_n, 32) // 32 to ensure AVX compatability (16 otherwise) + #define hv_free(x) _mm_free(x) +#else + #define hv_malloc(_n) malloc(_n) + #define hv_free(_n) free(_n) +#endif +#define hv_realloc(a, b) realloc(a, b) +#define hv_memcpy(a, b, c) memcpy(a, b, c) +#define hv_memset(a, b) memset(a, 0, b) + +// Strings +#define hv_strlen(a) strlen(a) +#define hv_strncat(a, b, c) strncat(a, b, c) +#define hv_strncpy(a, b, c) strncpy(a, b, c) +#define hv_strcmp(a, b) strcmp(a, b) +#define hv_strncmp(a, b, c) strncmp(a, b, c) +#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) + +// Math +#define hv_max_f(a, b) fmaxf(a, b) +#define hv_min_f(a, b) fminf(a, b) +#define hv_max_d(a, b) fmax(a, b) +#define hv_min_d(a, b) fmin(a, b) +#define hv_sin_f(a) sinf(a) +#define hv_sinh_f(a) sinhf(a) +#define hv_cos_f(a) cosf(a) +#define hv_cosh_f(a) coshf(a) +#define hv_tan_f(a) tanf(a) +#define hv_tanh_f(a) tanhf(a) +#define hv_asin_f(a) asinf(a) +#define hv_asinh_f(a) asinhf(a) +#define hv_acos_f(a) acosf(a) +#define hv_acosh_f(a) acoshf(a) +#define hv_atan_f(a) atanf(a) +#define hv_atanh_f(a) atanhf(a) +#define hv_atan2_f(a, b) atan2f(a, b) +#define hv_exp_f(a) expf(a) +#define hv_abs_f(a) fabsf(a) +#define hv_sqrt_f(a) sqrtf(a) +#define hv_log_f(a) logf(a) +#define hv_log2_f(a) log2f(a) +#define hv_log10_f(a) log10f(a) +#define hv_ceil_f(a) ceilf(a) +#define hv_floor_f(a) floorf(a) +#define hv_round_f(a) roundf(a) +#define hv_pow_f(a, b) powf(a, b) +#define hv_fma_f(a, b, c) ((a*b)+c) // TODO(joe): use 'fmaf(a, b, c)' once emscripten supports it + +// Utilities +#define hv_assert(e) assert(e) +#define hv_clear_buffer(b, n) memset(b, 0, n*sizeof(float)) + +#endif // HV_UNIX +#endif // _HEAVY_UTILS_UNIX_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils_windows.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Utils_windows.h" + +#if HV_WIN + +hv_size_t hv_max_ui(hv_size_t x, hv_size_t y) { + return (x >= y) ? x : y; +} + +hv_size_t hv_min_ui(hv_size_t x, hv_size_t y) { + return (x <= y) ? x : y; +} + +int hv_max_i(int x, int y) { + return (x >= y) ? x : y; +} + +int hv_min_i(int x, int y) { + return (x <= y) ? x : y; +} + +hv_uint32_t hv_min_max_log2(hv_uint32_t x) { +#if HV_MSVC + // finds ceil(log2(x)) + // http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + // http://msdn.microsoft.com/en-us/library/fbxyd7zd%28v=VS.80%29.aspx + unsigned long z = 0; + _BitScanReverse(&z, x); + return (hv_uint32_t) (z+1); +#else + return (hv_uint32_t) ((8 * sizeof(unsigned int)) - __builtin_clz(x-1)); +#endif // HV_MSVC +} + +#if HV_MSVC +int hv_snprintf(char* str, hv_size_t size, const char* format, ...) { + // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + int count = -1; + va_list ap; + va_start(ap, format); + + if (size != 0) { + count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + } + if (count == -1) { + count = _vscprintf(format, ap); + } + va_end(ap); + return count; +} +#endif // HV_MSVC +#endif // HV_WIN +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/Utils_windows.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_WINDOWS_H_ +#define _HEAVY_UTILS_WINDOWS_H_ + +#include "Utils.h" + +#if HV_WIN +#define _USE_MATH_DEFINES +#if HV_SIMD_AVX || HV_SIMD_SSE +#if HV_MSVC +#include <intrin.h> +#else +#include <immintrin.h> +#endif +#elif HV_SIMD_NEON +#include <arm_neon.h> +#endif +#include <malloc.h> +#include <assert.h> +#include <math.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +#define HV_EXPORT __declspec(dllexport) + +// MSVC Specific +#if HV_MSVC +#define inline __inline +#define HV_FORCE_INLINE __forceinline +#else +#define HV_FORCE_INLINE inline __attribute__((always_inline)) +#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) +#endif // HV_MSVC + +// Memory management +#define hv_alloca(_n) _alloca(_n) +#if !defined(HV_SIMD_AVX) || !defined(HV_SIMD_SSE) +#define hv_malloc(_n) _aligned_malloc(_n, 32) +#define hv_free(x) _aligned_free(x) +#else +#define hv_malloc(_n) malloc(_n) +#define hv_free(_n) free(_n) +#endif +#define hv_realloc(a, b) realloc(a, b) +#define hv_memcpy(a, b, c) memcpy(a, b, c) +#define hv_memset(a, b) memset(a, 0, b) + +// Strings +#define hv_strncat(a, b, c) strncat(a, b, c) +#define hv_strcmp(a, b) strcmp(a, b) +#define hv_strncmp(a, b, c) strncmp(a, b, c) +#define hv_strncpy(a, b, c) strncpy(a, b, c) +#define hv_strlen(a) strlen(a) + +// Math +#define hv_max_f(a, b) fmaxf(a, b) +#define hv_min_f(a, b) fminf(a, b) +#define hv_max_d(a, b) fmax(a, b) +#define hv_min_d(a, b) fmin(a, b) +#define hv_sin_f(a) sinf(a) +#define hv_sinh_f(a) sinhf(a) +#define hv_cos_f(a) cosf(a) +#define hv_cosh_f(a) coshf(a) +#define hv_tan_f(a) tanf(a) +#define hv_tanh_f(a) tanhf(a) +#define hv_asin_f(a) asinf(a) +#define hv_asinh_f(a) asinhf(a) +#define hv_acos_f(a) acosf(a) +#define hv_acosh_f(a) acoshf(a) +#define hv_atan_f(a) atanf(a) +#define hv_atanh_f(a) atanhf(a) +#define hv_atan2_f(a, b) atan2f(a, b) +#define hv_exp_f(a) expf(a) +#define hv_abs_f(a) fabsf(a) +#define hv_sqrt_f(a) sqrtf(a) +#define hv_log_f(a) logf(a) +#define hv_log2_f(a) log2f(a) +#define hv_log10_f(a) log10f(a) +#define hv_ceil_f(a) ceilf(a) +#define hv_floor_f(a) floorf(a) +#define hv_round_f(a) roundf(a) +#define hv_pow_f(a, b) powf(a, b) +#define hv_fma_f(a, b, c) ((a*b)+c) // TODO(joe): use 'fmaf(a, b, c)' once emscripten supports it + +// Utilities +#define hv_assert(e) assert(e) +#define hv_clear_buffer(b, n) memset(b, 0, n*sizeof(float)) + +#endif // HV_WIN +#endif // _HEAVY_UTILS_WINDOWS_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/hello-world/render.cpp Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,183 @@ +/* + * render.cpp + * + * Template render.cpp file for on-board heavy compiling + * + * N.B. this is currently *not* compatible with foleyDesigner source files! + * + * Created on: November 5, 2015 + * + * Christian Heinrichs + * + */ + +#include <BeagleRT.h> +#include <cmath> +#include "../include/Utilities.h" +#include "Heavy_bbb.h" + +// #include "I2c_TouchKey.h" + +// #include "../include/UdpServer.h" +// #include "../include/UdpClient.h" +// #include <iostream> +// #include <fstream> +// #include "../include/ReceiveAudioThread.h" + +// #include "../include/render.h" +// #include <arm_neon.h> +// #include <time.h> +// #include <sndfile.h> + +// #include "../include/RTAudio.h" +// #include <rtdk.h> + + +/* + * HEAVY CONTEXT & BUFFERS + */ + +Hv_bbb *gHeavyContext; +float *gHvInputBuffers = NULL, *gHvOutputBuffers = NULL; +int gHvInputChannels = 0, gHvOutputChannels = 0; + +float gInverseSampleRate; + +/* + * HEAVY FUNCTIONS + */ + +void printHook(double timestampSecs, const char *printLabel, const char *msgString, void *userData) { + printf("Message from Heavy patch: [@ %.3f] %s: %s\n", timestampSecs, printLabel, msgString); +} + +static void sendHook( + double timestamp, // in milliseconds + const char *receiverName, + const HvMessage *const m, + void *userData) { + + // only react to messages sent to receivers named "hello" + if (!strncmp(receiverName, "hello", 5)) { + } + +} + +/* + * RENDER INITIALISATION, LOOP & CLEANUP + */ + + +// bool initialise_render(int numMatrixChannels, int numAudioChannels, +// int numMatrixFramesPerPeriod, +// int numAudioFramesPerPeriod, +// float matrixSampleRate, float audioSampleRate, +// void *userData) +// { +bool setup(BeagleRTContext *context, void *userData) { + + /* HEAVY */ + + gHeavyContext = hv_bbb_new(context->audioSampleRate); + + gHvInputChannels = hv_getNumInputChannels(gHeavyContext); + gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext); + + // srand ( time(NULL) ); + + rt_printf("Starting Heavy context with %d input channels and %d output channels\n", + gHvInputChannels, gHvOutputChannels); + + if(gHvInputChannels != 0) { + gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float)); + //memset(gHvInputBuffers,0,gHvInputChannels * numAudioFramesPerPeriod * sizeof(float)); + } + if(gHvOutputChannels != 0) { + gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float)); + } + + gInverseSampleRate = 1.0 / context->audioSampleRate; + + // Set heavy print hook + hv_setPrintHook(gHeavyContext, &printHook); + // Set heavy send hook + hv_setSendHook(gHeavyContext, sendHook); + + return true; +} + + +// void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, +// uint16_t *matrixIn, uint16_t *matrixOut) +// { +void render(BeagleRTContext *context, void *userData) +{ + // use this for thread management + // if(gCount == 0) { + // } else { + // } + // gCount++; + + // De-interleave the data + if(gHvInputBuffers != NULL) { + for(int n = 0; n < context->audioFrames; n++) { + for(int ch = 0; ch < gHvInputChannels; ch++) { + if(ch >= context->audioChannels+context->analogChannels) { + // THESE ARE PARAMETER INPUT 'CHANNELS' USED FOR ROUTING + // 'sensor' outputs from routing channels of dac~ are passed through here + break; + } else { + // If more than 2 ADC inputs are used in the pd patch, route the analog inputs + // i.e. ADC3->analogIn0 etc. (first two are always audio inputs) + if(ch >= context->audioChannels) { + int m = n/2; + float mIn = context->analogIn[m*context->analogChannels + (ch-context->audioChannels)]; + gHvInputBuffers[ch * context->audioFrames + n] = mIn; + } else { + gHvInputBuffers[ch * context->audioFrames + n] = context->audioIn[n * context->audioChannels + ch]; + } + } + } + } + } + + // replacement for bang~ object + //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b"); + + hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames); + + // Interleave the output data + if(gHvOutputBuffers != NULL) { + for(int n = 0; n < context->audioFrames; n++) { + + for(int ch = 0; ch < gHvOutputChannels; ch++) { + if(ch >= context->audioChannels+context->analogChannels) { + // THESE ARE SENSOR OUTPUT 'CHANNELS' USED FOR ROUTING + // they are the content of the 'sensor output' dac~ channels + } else { + if(ch >= context->audioChannels) { + int m = n/2; + // float mOut = (float)gHvOutputBuffers[ch*numAudioFrames + n]; + // mOut = constrain(mOut,0.0,1.0); + context->analogOut[m * context->analogFrames + (ch-context->audioChannels)] = constrain(gHvOutputBuffers[ch*context->audioFrames + n],0.0,1.0); + } else { + context->audioOut[n * context->audioChannels + ch] = gHvOutputBuffers[ch * context->audioFrames + n]; + } + } + } + } + } + +} + + +void cleanup(BeagleRTContext *context, void *userData) +{ + + hv_bbb_free(gHeavyContext); + if(gHvInputBuffers != NULL) + free(gHvInputBuffers); + if(gHvOutputBuffers != NULL) + free(gHvOutputBuffers); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/pd/hello-world/_main.pd Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,19 @@ +#N canvas 275 504 617 247 10; +#X text 304 48 ├┴┐├┤-├─┤│-┬│--├┤-╠╦╝-║- +; +#X text 304 36 ┌┐-┌─┐┌─┐┌─┐┬--┌─┐╦═╗╔╦╗ +; +#X text 304 57 └─┘└─┘┴-┴└─┘┴─┘└─┘╩╚═-╩- +; +#X text 353 76 powered by heavy; +#X text 299 68 -------------------------; +#X text 340 101 http://beaglert.cc; +#X obj 55 192 dac~ 1 2; +#X obj 55 151 *~ 0.1; +#X obj 55 130 osc~ 440; +#X text 51 51 Hello world!; +#X text 51 61 ============; +#X text 111 128 (the sweet sound of success); +#X connect 7 0 6 1; +#X connect 7 0 6 0; +#X connect 8 0 7 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/pd/samphold/_main.pd Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,29 @@ +#N canvas 275 504 617 247 10; +#X text 304 48 ├┴┐├┤-├─┤│-┬│--├┤-╠╦╝-║- +; +#X text 304 36 ┌┐-┌─┐┌─┐┌─┐┬--┌─┐╦═╗╔╦╗ +; +#X text 304 57 └─┘└─┘┴-┴└─┘┴─┘└─┘╩╚═-╩- +; +#X text 353 76 powered by heavy; +#X text 299 68 -------------------------; +#X text 340 101 http://beaglert.cc; +#X obj 55 212 dac~ 1 2; +#X obj 55 171 *~ 0.1; +#X obj 55 150 osc~ 440; +#X text 111 148 (the sweet sound of success); +#X obj 55 61 noise~; +#X obj 55 128 samphold~; +#X text 51 21 ==================; +#X text 51 11 Sample and hold FM; +#X obj 55 85 lop~ 1; +#X obj 122 107 phasor~ 880; +#X obj 55 107 *~ 1e+06; +#X connect 7 0 6 1; +#X connect 7 0 6 0; +#X connect 8 0 7 0; +#X connect 10 0 14 0; +#X connect 11 0 8 0; +#X connect 14 0 16 0; +#X connect 15 0 11 1; +#X connect 16 0 11 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlBinop.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlBinop.h" + +hv_size_t cBinop_init(ControlBinop *o, float k) { + o->k = k; + return 0; +} + +static float cBinop_perform_op(BinopType op, float f, const float k) { + switch (op) { + case HV_BINOP_ADD: return f + k; + case HV_BINOP_SUBTRACT: return f - k; + case HV_BINOP_MULTIPLY: return f * k; + case HV_BINOP_DIVIDE: return (k != 0.0f) ? f / k : 0.0f; + case HV_BINOP_INT_DIV: return (float) ((int) f / (int) k); + case HV_BINOP_MOD_BIPOLAR: return (float) ((int) f % (int) k); + case HV_BINOP_MOD_UNIPOLAR: { + f = (k == 0.0f) ? 0.0f : (float) ((int) f % (int) k); + return (f < 0.0f) ? f + fabsf(k) : f; + } + case HV_BINOP_BIT_LEFTSHIFT: return (float) (((int) f) << ((int) k)); + case HV_BINOP_BIT_RIGHTSHIFT: return (float) (((int) f) >> ((int) k)); + case HV_BINOP_BIT_AND: return (float) ((int) f & (int) k); + case HV_BINOP_BIT_XOR: return (float) ((int) f ^ (int) k); + case HV_BINOP_BIT_OR: return (float) ((int) f | (int) k); + case HV_BINOP_EQ: return (f == k) ? 1.0f : 0.0f; + case HV_BINOP_NEQ: return (f != k) ? 1.0f : 0.0f; + case HV_BINOP_LOGICAL_AND: return ((f == 0.0f) || (k == 0.0f)) ? 0.0f : 1.0f; + case HV_BINOP_LOGICAL_OR: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : 1.0f; + case HV_BINOP_LESS_THAN: return (f < k) ? 1.0f : 0.0f; + case HV_BINOP_LESS_THAN_EQL: return (f <= k) ? 1.0f : 0.0f; + case HV_BINOP_GREATER_THAN: return (f > k) ? 1.0f : 0.0f; + case HV_BINOP_GREATER_THAN_EQL: return (f >= k) ? 1.0f : 0.0f; + case HV_BINOP_MAX: return hv_max_f(f, k); + case HV_BINOP_MIN: return hv_min_f(f, k); + case HV_BINOP_POW: return (f > 0.0f) ? powf(f, k) : 0.0f; + case HV_BINOP_ATAN2: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : atan2f(f, k); + default: return 0.0f; + } +} + +void cBinop_onMessage(HvBase *_c, ControlBinop *o, BinopType op, int letIn, + const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + switch (letIn) { + case 0: { + if (msg_isFloat(m, 0)) { + // Note(joe): supporting Pd's ability to perform operations of packs + // of floats is likely to not be supported in the future. + if (msg_isFloat(m, 1)) o->k = msg_getFloat(m, 1); + HvMessage *n = HV_MESSAGE_ON_STACK(1); + float f = cBinop_perform_op(op, msg_getFloat(m, 0), o->k); + msg_initWithFloat(n, msg_getTimestamp(m), f); + sendMessage(_c, 0, n); + } + break; + } + case 1: { + if (msg_isFloat(m, 0)) { + o->k = msg_getFloat(m, 0); + } + break; + } + default: break; + } +} + +void cBinop_k_onMessage(HvBase *_c, void *o, BinopType op, const float k, + int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + if (msg_isFloat(m, 0)) { + // NOTE(mhroth): Heavy does not support sending bangs to binop objects to return the previous output + float f = (msg_isFloat(m, 1)) ? msg_getFloat(m, 1) : k; + HvMessage *n = HV_MESSAGE_ON_STACK(1); + f = cBinop_perform_op(op, msg_getFloat(m, 0), f); + msg_initWithFloat(n, msg_getTimestamp(m), f); + sendMessage(_c, 0, n); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlBinop.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_BINOP_H_ +#define _HEAVY_CONTROL_BINOP_H_ + +#include "HvBase.h" + +typedef enum BinopType { + HV_BINOP_ADD, + HV_BINOP_SUBTRACT, + HV_BINOP_MULTIPLY, + HV_BINOP_DIVIDE, + HV_BINOP_INT_DIV, + HV_BINOP_MOD_BIPOLAR, + HV_BINOP_MOD_UNIPOLAR, + HV_BINOP_BIT_LEFTSHIFT, + HV_BINOP_BIT_RIGHTSHIFT, + HV_BINOP_BIT_AND, + HV_BINOP_BIT_XOR, + HV_BINOP_BIT_OR, + HV_BINOP_EQ, + HV_BINOP_NEQ, + HV_BINOP_LOGICAL_AND, + HV_BINOP_LOGICAL_OR, + HV_BINOP_LESS_THAN, + HV_BINOP_LESS_THAN_EQL, + HV_BINOP_GREATER_THAN, + HV_BINOP_GREATER_THAN_EQL, + HV_BINOP_MAX, + HV_BINOP_MIN, + HV_BINOP_POW, + HV_BINOP_ATAN2 +} BinopType; + +typedef struct ControlBinop { + float k; +} ControlBinop; + +hv_size_t cBinop_init(ControlBinop *o, float k); + +void cBinop_onMessage(HvBase *_c, ControlBinop *o, BinopType op, int letIn, + const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +void cBinop_k_onMessage(HvBase *_c, void *o, BinopType op, const float k, + int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +#endif // _HEAVY_CONTROL_BINOP_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlRandom.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlRandom.h" +#include "HvBase.h" + +// http://www.firstpr.com.au/dsp/rand31 +// http://en.wikipedia.org/wiki/Lehmer_random_number_generator + +hv_size_t cRandom_init(ControlRandom *o, int seed) { + o->state = (seed != 0) ? seed : 1; + return 0; +} + +void cRandom_onMessage(HvBase *_c, ControlRandom *o, int inletIndex, const HvMessage *m, + void (*sendMessage)(HvBase *, int, const HvMessage *)) { + switch (inletIndex) { + case 0: { + HvMessage *n = HV_MESSAGE_ON_STACK(1); + o->state = (int) ((((unsigned long long) o->state) * 279470273UL) % 4294967291UL); + float f = ((float) (o->state >> 9)) * 0.00000011920929f; + msg_initWithFloat(n, msg_getTimestamp(m), f); + sendMessage(_c, 0, n); + break; + } + case 1: { + if (msg_isFloat(m,0)) { + o->state = (int) msg_getFloat(m,0); + } + break; + } + default: break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlRandom.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_RANDOM_H_ +#define _HEAVY_CONTROL_RANDOM_H_ + +#include "HvBase.h" + +typedef struct ControlRandom { + unsigned int state; +} ControlRandom; + +hv_size_t cRandom_init(ControlRandom *o, int seed); + +void cRandom_onMessage(HvBase *_c, ControlRandom *o, int letIndex, const HvMessage *m, + void (*sendMessage)(HvBase *, int, const HvMessage *)); + +#endif // _HEAVY_CONTROL_RANDOM_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlSystem.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlSystem.h" +#include "HvTable.h" + +void cSystem_onMessage(HvBase *_c, void *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + + HvMessage *n = HV_MESSAGE_ON_STACK(1); + if (msg_compareSymbol(m, 0, "samplerate")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) ctx_getSampleRate(_c)); + } else if (msg_compareSymbol(m, 0, "numInputChannels")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) ctx_getNumInputChannels(_c)); + } else if (msg_compareSymbol(m, 0, "numOutputChannels")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) ctx_getNumOutputChannels(_c)); + } else if (msg_compareSymbol(m, 0, "currentTime")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) msg_getTimestamp(m)); + } else if (msg_compareSymbol(m, 0, "table")) { + // NOTE(mhroth): no need to check message format for symbols as table lookup will fail otherwise + HvTable *o = ctx_getTableForHash(_c, msg_getHash(m,1)); + if (o != NULL) { + if (msg_compareSymbol(m, 2, "length")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getLength(o)); + } else if (msg_compareSymbol(m, 2, "size")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o)); + } else if (msg_compareSymbol(m, 2, "head")) { + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(o)); + } else return; + } else return; + } else return; + sendMessage(_c, 0, n); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlSystem.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_SYSTEM_H_ +#define _HEAVY_CONTROL_SYSTEM_H_ + +#include "HvBase.h" + +void cSystem_onMessage(HvBase *_c, void *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +#endif // _HEAVY_CONTROL_SYSTEM_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlUnop.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlUnop.h" +#include "HvBase.h" + +void cUnop_onMessage(HvBase *_c, UnopType op, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const )) { + if (msg_isFloat(m, 0)) { + float f = msg_getFloat(m, 0); + switch (op) { + case HV_UNOP_SIN: f = hv_sin_f(f); break; + case HV_UNOP_SINH: f = hv_sinh_f(f); break; + case HV_UNOP_COS: f = hv_cos_f(f); break; + case HV_UNOP_COSH: f = hv_cosh_f(f); break; + case HV_UNOP_TAN: f = hv_tan_f(f); break; + case HV_UNOP_TANH: f = hv_tanh_f(f); break; + case HV_UNOP_ASIN: f = hv_asin_f(f); break; + case HV_UNOP_ASINH: f = hv_asinh_f(f); break; + case HV_UNOP_ACOS: f = hv_acos_f(f); break; + case HV_UNOP_ACOSH: f = hv_acosh_f(f); break; + case HV_UNOP_ATAN: f = hv_atan_f(f); break; + case HV_UNOP_ATANH: f = hv_atanh_f(f); break; + case HV_UNOP_EXP: f = hv_exp_f(f); break; + case HV_UNOP_ABS: f = hv_abs_f(f); break; + case HV_UNOP_SQRT: f = (f > 0.0f) ? hv_sqrt_f(f) : 0.0f; break; + case HV_UNOP_LOG: f = (f > 0.0f) ? hv_log_f(f) : 0.0f; break; + case HV_UNOP_LOG2: f = (f > 0.0f) ? hv_log2_f(f) : 0.0f; break; + case HV_UNOP_LOG10: f = (f > 0.0f) ? hv_log10_f(f) : 0.0f; break; + case HV_UNOP_CEIL: f = hv_ceil_f(f); break; + case HV_UNOP_FLOOR: f = hv_floor_f(f); break; + case HV_UNOP_ROUND: f = hv_round_f(f); break; + default: return; + } + HvMessage *n = HV_MESSAGE_ON_STACK(1); + msg_initWithFloat(n, m->timestamp, f); + sendMessage(_c, 0, n); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlUnop.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_UNOP_H_ +#define _HEAVY_CONTROL_UNOP_H_ + +struct HvBase; +struct HvMessage; + +typedef enum UnopType { + HV_UNOP_ASIN, + HV_UNOP_ASINH, + HV_UNOP_ACOS, + HV_UNOP_ACOSH, + HV_UNOP_ATAN, + HV_UNOP_ATANH, + HV_UNOP_SIN, + HV_UNOP_SINH, + HV_UNOP_COS, + HV_UNOP_COSH, + HV_UNOP_TAN, + HV_UNOP_TANH, + HV_UNOP_EXP, + HV_UNOP_ABS, + HV_UNOP_SQRT, + HV_UNOP_LOG, + HV_UNOP_LOG2, + HV_UNOP_LOG10, + HV_UNOP_CEIL, + HV_UNOP_FLOOR, + HV_UNOP_ROUND +} UnopType; + +void cUnop_onMessage(struct HvBase *_c, UnopType op, const struct HvMessage *const m, + void (*sendMessage)(struct HvBase *, int, const struct HvMessage *const)); + +#endif // _HEAVY_CONTROL_UNOP_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlVar.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ControlVar.h" + +hv_size_t cVar_init_f(ControlVar *o, float k) { + o->e.type = FLOAT; + o->e.data.f = k; + return 0; +} + +hv_size_t cVar_init_s(ControlVar *o, const char *s) { + o->e.type = HASH; + o->e.data.h = msg_symbolToHash(s); + return 0; +} + +void cVar_free(ControlVar *o) { + // nothing to do +} + +void cVar_onMessage(HvBase *_c, ControlVar *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + switch (letIn) { + case 0: { + switch (msg_getType(m,0)) { + case BANG: { + HvMessage *n = HV_MESSAGE_ON_STACK(1); + if (o->e.type == FLOAT) msg_initWithFloat(n, msg_getTimestamp(m), o->e.data.f); + else if (o->e.type == HASH) msg_initWithHash(n, msg_getTimestamp(m), o->e.data.h); + else return; + sendMessage(_c, 0, n); + break; + } + case FLOAT: { + o->e.type = FLOAT; + o->e.data.f = msg_getFloat(m,0); + sendMessage(_c, 0, m); + break; + } + case SYMBOL: + case HASH: { + o->e.type = HASH; + o->e.data.h = msg_getHash(m,0); + sendMessage(_c, 0, m); + break; + } + default: return; + } + break; + } + case 1: { + switch (msg_getType(m,0)) { + case FLOAT: { + o->e.type = FLOAT; + o->e.data.f = msg_getFloat(m,0); + break; + } + case SYMBOL: + case HASH: { + o->e.type = HASH; + o->e.data.h = msg_getHash(m,0); + break; + } + default: break; + } + } + default: return; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/ControlVar.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_CONTROL_VAR_H_ +#define _HEAVY_CONTROL_VAR_H_ + +#include "HvBase.h" + +typedef struct ControlVar { + Element e; // type is only every FLOAT or HASH +} ControlVar; + +hv_size_t cVar_init_f(ControlVar *o, float k); + +hv_size_t cVar_init_s(ControlVar *o, const char *s); + +void cVar_free(ControlVar *o); + +void cVar_onMessage(HvBase *_c, ControlVar *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +#endif // _HEAVY_CONTROL_VAR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Heavy.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvBase.h" +#include "HvTable.h" + +#if !HV_WIN +#pragma mark - Heavy Table +#endif + +int hv_table_resize(HvTable *o, hv_uint32_t newLength) { + return hTable_resize(o, newLength); +} + +float *hv_table_getBuffer(HvTable *o) { + return hTable_getBuffer(o); +} + +hv_size_t hv_table_getLength(HvTable *o) { + return hTable_getLength(o); +} + + + +#if !HV_WIN +#pragma mark - Heavy Message +#endif + +hv_size_t hv_msg_getByteSize (hv_uint32_t numElements) { + return msg_getByteSize(numElements); +} + +void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) { + msg_init(m, numElements, timestamp); +} + +hv_size_t hv_msg_getNumElements(const HvMessage *const m) { + return msg_getNumElements(m); +} + +double hv_msg_getTimestamp(const HvMessage *const m) { + return msg_getTimestamp(m); +} + +void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) { + msg_setTimestamp(m, timestamp); +} + +bool hv_msg_isBang(const HvMessage *const m, int i) { + return msg_isBang(m,i); +} + +void hv_msg_setBang(HvMessage *m, int i) { + msg_setBang(m,i); +} + +bool hv_msg_isFloat(const HvMessage *const m, int i) { + return msg_isFloat(m, i); +} + +float hv_msg_getFloat(const HvMessage *const m, int i) { + return msg_getFloat(m,i); +} + +void hv_msg_setFloat(HvMessage *m, int i, float f) { + msg_setFloat(m,i,f); +} + +bool hv_msg_isSymbol(const HvMessage *const m, int i) { + return msg_isSymbol(m,i); +} + +char *hv_msg_getSymbol(const HvMessage *const m, int i) { + return msg_getSymbol(m,i); +} + +void hv_msg_setSymbol(HvMessage *m, int i, char *s) { + msg_setSymbol(m,i,s); +} + +bool hv_msg_isHash(const HvMessage *const m, int i) { + return msg_isHash(m, i); +} + +unsigned int hv_msg_getHash(const HvMessage *const m, int i) { + return msg_getHash(m, i); +} + +bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) { + return msg_hasFormat(m, fmt); +} + +char *hv_msg_toString(const HvMessage *const m) { + return msg_toString(m); +} + +HvMessage *hv_msg_copy(HvMessage *m) { + return msg_copy(m); +} + +void hv_msg_free(HvMessage *m) { + msg_free(m); +} + + + +#if !HV_WIN +#pragma mark - Heavy Common +#endif + +double hv_getSampleRate(HvBase *c) { + return ctx_getSampleRate(c); +} + +int hv_getNumInputChannels(HvBase *c) { + return ctx_getNumInputChannels(c); +} + +int hv_getNumOutputChannels(HvBase *c) { + return ctx_getNumOutputChannels(c); +} + +const char *hv_getName(HvBase *c) { + return ctx_getName(c); +} + +void hv_setPrintHook(HvBase *c, void (*f)(double, const char *, const char *, void *)) { + ctx_setPrintHook(c, f); +} + +void hv_setSendHook(HvBase *c, void (*f)(double, const char *, const HvMessage *const, void *)) { + ctx_setSendHook(c, f); +} + +void hv_vscheduleMessageForReceiver(HvBase *c, const char *receiverName, const double delayMs, const char *format, ...) { + va_list ap; + va_start(ap, format); + + const int numElem = (int) hv_strlen(format); + HvMessage *m = HV_MESSAGE_ON_STACK(numElem); + msg_init(m, numElem, c->blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*ctx_getSampleRate(c)/1000.0)); + for (int i = 0; i < numElem; i++) { + switch (format[i]) { + case 'b': msg_setBang(m,i); break; + case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; + case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; + default: break; + } + } + ctx_scheduleMessageForReceiver(c, receiverName, m); + + va_end(ap); +} + +void hv_scheduleMessageForReceiver(HvBase *c, const char *receiverName, double delayMs, HvMessage *m) { + hv_assert(delayMs >= 0.0); + msg_setTimestamp(m, c->blockStartTimestamp + (hv_uint32_t) (delayMs*ctx_getSampleRate(c)/1000.0)); + ctx_scheduleMessageForReceiver(c, receiverName, m); +} + +HvTable *hv_getTableForName(HvBase *c, const char *tableName) { + return ctx_getTableForName(c, tableName); +} + +void hv_cancelMessage(HvBase *c, HvMessage *m) { + ctx_cancelMessage(c, m, NULL); +} + +double hv_getCurrentTime(HvBase *c) { + return ((double) c->blockStartTimestamp)/c->sampleRate; +} + +void *hv_getUserData(HvBase *c) { + return ctx_getUserData(c); +} + +void hv_setUserData(HvBase *c, void *userData) { + ctx_setUserData(c, userData); +} + +void hv_setBasePath(HvBase *c, const char *basePath) { + ctx_setBasePath(c, basePath); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HeavyMath.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,645 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_MATH_H_ +#define _HEAVY_MATH_H_ + +#include "Utils.h" + +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/ +// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html +// http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html + +static inline void __hv_zero_f(hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + *bOut = _mm_setzero_ps(); +#elif HV_SIMD_NEON + *bOut = vdupq_n_f32(0.0f); +#else // HV_SIMD_NONE + *bOut = 0.0f; +#endif +} + +static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_load_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_load_ps(bIn); +#elif HV_SIMD_NEON + *bOut = vld1q_f32(bIn); +#else // HV_SIMD_NONE + *bOut = *bIn; +#endif +} + +static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) { +#if HV_SIMD_AVX + _mm256_store_ps(bOut, bIn); +#elif HV_SIMD_SSE + _mm_store_ps(bOut, bIn); +#elif HV_SIMD_NEON + vst1q_f32(bOut, bIn); +#else // HV_SIMD_NONE + *bOut = bIn; +#endif +} + +static inline void __hv_log_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_log_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_log_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_log_f() not implemented +#else // HV_SIMD_NONE + *bOut = (bIn > 0.0f) ? hv_log_f(bIn) : 0.0f; +#endif +} + +static inline void __hv_log10_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_log10_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_log10_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_log10_f() not implemented +#else // HV_SIMD_NONE + *bOut = (bIn > 0.0f) ? hv_log10_f(bIn) : 0.0f; +#endif +} + +static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_log2_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_log2_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_log2_f() not implemented +#else // HV_SIMD_NONE + *bOut = (bIn > 0.0f) ? hv_log2_f(bIn) : 0.0f; +#endif +} + +// NOTE(mhroth): this is a pretty ghetto implementation +static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_set_ps( + hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]), + hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0])); +#elif HV_SIMD_SSE + *bOut = _mm_set_ps(hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0])); +#elif HV_SIMD_NEON + *bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])}; +#else // HV_SIMD_NONE + *bOut = hv_cos_f(bIn); +#endif +} + +static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_acos_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_acos_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_acos_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_acos_f(bIn); +#endif +} + +static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_cosh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_cosh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_cosh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_cosh_f(bIn); +#endif +} + +static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_acosh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_acosh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_acosh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_acosh_f(bIn); +#endif +} + +static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_sin_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_sin_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_sin_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_sin_f(bIn); +#endif +} + +static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_asin_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_asin_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_asin_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_asin_f(bIn); +#endif +} + +static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_sinh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_sinh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_sinh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_sinh_f(bIn); +#endif +} + +static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_asinh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_asinh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_asinh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_asinh_f(bIn); +#endif +} + +static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_tan_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_tan_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_tan_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_tan_f(bIn); +#endif +} + +static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_atan_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_atan_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_atan_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_atan_f(bIn); +#endif +} + +static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_atan2_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_atan2_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_atan2_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_atan2_f(bIn0, bIn1); +#endif +} + +static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_tanh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_tanh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_tanh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_tanh_f(bIn); +#endif +} + +static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_atanh_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_atanh_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_atanh_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_atanh_f(bIn); +#endif +} + +// NOTE(mhroth): use of sqrt is absolute and total MURDER. Make do with recipocal sqrt if possible!! +static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_sqrt_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_sqrt_ps(bIn); +#elif HV_SIMD_NEON +#warning __hv_sqrt_f() numerical results may be inexact + *bOut = vrecpeq_f32(vrsqrteq_f32(bIn)); +#else // HV_SIMD_NONE + *bOut = hv_sqrt_f(bIn); +#endif +} + +static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_rsqrt_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_rsqrt_ps(bIn); +#elif HV_SIMD_NEON +#warning __hv_rsqrt_f() numerical results may be inexact + *bOut = vrsqrteq_f32(bIn); +#else // HV_SIMD_NONE + *bOut = 1.0f/hv_sqrt_f(bIn); +#endif +} + +static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn); +#elif HV_SIMD_SSE + *bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31 +#elif HV_SIMD_NEON + *bOut = vabsq_f32(bIn); +#else // HV_SIMD_NONE + *bOut = hv_abs_f(bIn); +#endif +} + +static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_exp_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_exp_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_exp_f() not implemented +#else // HV_SIMD_NONE + *bOut = hv_exp_f(bIn); +#endif +} + +static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_ceil_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_ceil_ps(bIn); +#elif HV_SIMD_NEON +#if __ARM_ARCH >= 8 + *bOut = vrndpq_f32(bIn); +#else +#warning A slow NEON implementation of __hv_ceil_f() is being used because the necessary intrinsic cannot be found. It is only available in ARMv8. + *bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])}; +#endif // vrndpq_f32 +#else // HV_SIMD_NONE + *bOut = hv_ceil_f(bIn); +#endif +} + +static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_floor_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_floor_ps(bIn); +#elif HV_SIMD_NEON +#if __ARM_ARCH >= 8 + *bOut = vrndmq_f32(bIn); +#else +#warning A slow NEON implementation of __hv_floor_f() is being used because the necessary intrinsic cannot be found. It is only available in ARMv8. + *bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])}; +#endif // vrndmq_f32 +#else // HV_SIMD_NONE + *bOut = hv_floor_f(bIn); +#endif +} + +// __add~f +static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_add_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_add_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vaddq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 + bIn1; +#endif +} + +// __add~i +static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_add_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vaddq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 + bIn1; +#endif +} + +// __sub~f +static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_sub_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_sub_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vsubq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 - bIn1; +#endif +} + +// __mul~f +static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_mul_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_mul_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmulq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 * bIn1; +#endif +} + +// __*~i +static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_mullo_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmulq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = bIn0 * bIn1; +#endif +} + +// __cast~if +static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cvtepi32_ps(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_cvtepi32_ps(bIn); +#elif HV_SIMD_NEON + *bOut = vcvtq_f32_s32(bIn); +#else // HV_SIMD_NONE + *bOut = (float) bIn; +#endif +} + +// __cast~fi +static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cvtps_epi32(bIn); +#elif HV_SIMD_SSE + *bOut = _mm_cvtps_epi32(bIn); +#elif HV_SIMD_NEON + *bOut = vcvtq_s32_f32(bIn); +#else // HV_SIMD_NONE + *bOut = (int) bIn; +#endif +} + +static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_div_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_div_ps(bIn0, bIn1); +#elif HV_SIMD_NEON +#warning __hv_div_f() numerical results may be inexact + *bOut = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f; +#endif +} + +static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_min_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_min_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vminq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_min_f(bIn0, bIn1); +#endif +} + +static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_min_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vminq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_min_i(bIn0, bIn1); +#endif +} + +static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_max_ps(bIn0, bIn1); +#elif HV_SIMD_SSE + *bOut = _mm_max_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmaxq_f32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_max_f(bIn0, bIn1); +#endif +} + +static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { +#if HV_SIMD_AVX + __m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); + __m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); + *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#elif HV_SIMD_SSE + *bOut = _mm_max_epi32(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vmaxq_s32(bIn0, bIn1); +#else // HV_SIMD_NONE + *bOut = hv_max_i(bIn0, bIn1); +#endif +} + +static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_set_ps( + hv_pow_f(bIn0[7], bIn1[7]), + hv_pow_f(bIn0[6], bIn1[6]), + hv_pow_f(bIn0[5], bIn1[5]), + hv_pow_f(bIn0[4], bIn1[4]), + hv_pow_f(bIn0[3], bIn1[3]), + hv_pow_f(bIn0[2], bIn1[2]), + hv_pow_f(bIn0[1], bIn1[1]), + hv_pow_f(bIn0[0], bIn1[0])); +#elif HV_SIMD_SSE + *bOut = _mm_set_ps( + hv_pow_f(bIn0[3], bIn1[3]), + hv_pow_f(bIn0[2], bIn1[2]), + hv_pow_f(bIn0[1], bIn1[1]), + hv_pow_f(bIn0[0], bIn1[0])); +#elif HV_SIMD_NEON + *bOut = (float32x4_t) { + hv_pow_f(bIn0[0], bIn1[0]), + hv_pow_f(bIn0[1], bIn1[1]), + hv_pow_f(bIn0[2], bIn1[2]), + hv_pow_f(bIn0[3], bIn1[3])}; +#else // HV_SIMD_NONE + *bOut = hv_pow_f(bIn0, bIn1); +#endif +} + +static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmpgt_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 > bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmpge_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmplt_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 < bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmple_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1)); +#else // HV_SIMD_NONE + *bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ); +#elif HV_SIMD_SSE + *bOut = _mm_cmpneq_ps(bIn0, bIn1); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1))); +#else // HV_SIMD_NONE + *bOut = (bIn0 != bIn1) ? 1.0f : 0.0f; +#endif +} + +static inline void __hv_xor_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_xor_f() not implemented +#elif HV_SIMD_SSE +#warning __hv_xor_f() not implemented +#elif HV_SIMD_NEON +#warning __hv_xor_f() not implemented +#else // HV_SIMD_NONE + *bOut = (float) (((int) bIn0) ^ ((int) bIn1)); +#endif +} + +static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_and_ps(bIn1, bIn0); +#elif HV_SIMD_SSE + *bOut = _mm_and_ps(bIn1, bIn0); +#elif HV_SIMD_NEON + *bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0))); +#else // HV_SIMD_NONE + if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f; + else if (bIn0 == 1.0f) *bOut = bIn1; + else if (bIn1 == 1.0f) *bOut = bIn0; + else hv_assert(0); // TODO(mhroth): floating point & is pretty much a bad idea, only used for if~ +#endif +} + +// bOut = (bIn0 * bIn1) + bIn2 +static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#if HV_SIMD_FMA + *bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2); +#else + *bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2); +#endif // HV_SIMD_FMA +#elif HV_SIMD_SSE +#if HV_SIMD_FMA + *bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2); +#else + *bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2); +#endif // HV_SIMD_FMA +#elif HV_SIMD_NEON +#if __ARM_ARCH >= 8 + *bOut = vfmaq_f32(bIn2, bIn0, bIn1); +#else + // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures + // But in fact ideally fma would be disabled in ir2c for ARM architectures. + // LLVM does a much better job handling fma than we do. + *bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2); +#endif +#else // HV_SIMD_NONE + *bOut = hv_fma_f(bIn0, bIn1, bIn2); +#endif +} + +#endif // _HEAVY_MATH_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Heavy_bbb.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,241 @@ + +/** + * Copyright (c) 2014,2015 Enzien Audio, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or + * sublicense copies of the Software, strictly on a non-commercial basis, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * DO NOT MODIFY. THIS CODE IS MACHINE GENERATED BY THE SECTION6 HEAVY COMPILER. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Utils.h" + +#if !HV_MSVC +#pragma mark - Heavy Table +#endif + +#ifndef _HEAVY_TABLE_H_ +#define _HEAVY_TABLE_H_ + +typedef struct HvTable HvTable; + +/** + * Resizes the table to the given length. Length must be positive. + * Existing contents are copied to the new table. Remaining space is cleared. + * The change in byte-size of the table is returned. A value of zero indicates error. + */ +HV_EXPORT int hv_table_resize(HvTable *o, hv_uint32_t newLength); + +/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */ +HV_EXPORT float *hv_table_getBuffer(HvTable *o); + +/** Returns the length of this table in samples. */ +HV_EXPORT int hv_table_getLength(HvTable *o); + +#endif // _HEAVY_TABLE_H_ + + + +#if !HV_MSVC +#pragma mark - Heavy Message +#endif + +#ifndef _HEAVY_MESSAGE_H_ +#define _HEAVY_MESSAGE_H_ + +HV_EXPORT typedef struct HvMessage HvMessage; + +/** Returns the byte size of a HvMessage with a number of elements on the heap. */ +HV_EXPORT hv_size_t hv_msg_getByteSize(int numElements); + +/** Create a HvMessage on the stack with a number of elements. This message MUST NOT be freed. */ +#define hv_msg_onStack(_n) ((HvMessage *) hv_alloca(hv_msg_getByteSize(_n))) + +/** Initialise a message with the number of elements and a timestamp (in milliseconds). */ +HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, double timestamp); + +/** Returns the number of elements in this message. */ +HV_EXPORT int hv_msg_getNumElements(const HvMessage *const m); + +/** Returns the time at which this message exists (in milliseconds). */ +HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *const m); + +/** Set the time at which this message should be executed (in milliseconds). */ +HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp); + +/** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i); + +/** Sets the indexed element to a bang. Index is not bounds checked. */ +HV_EXPORT void hv_msg_setBang(HvMessage *m, int i); + +/** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i); + +/** Returns the indexed element as a float value. Index is not bounds checked. */ +HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i); + +/** Sets the indexed element to float value. Index is not bounds checked. */ +HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f); + +/** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i); + +/** Returns the indexed element as a symbol value. Index is not bounds checked. */ +HV_EXPORT char *hv_msg_getSymbol(const HvMessage *const m, int i); + +/** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */ +HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i); + +/** Returns the indexed element as a hash value. Index is not bounds checked. */ +HV_EXPORT unsigned int hv_msg_getHash(const HvMessage *const m, int i); + +/** Sets the indexed element to symbol value. Index is not bounds checked. */ +HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s); + +/** + * Returns true if the message has the given format, in number of elements and type. False otherwise. + * Valid element types are: + * 'b': bang + * 'f': float + * 's': symbol + * + * For example, a message with three floats would have a format of "fff". A single bang is "b". + * A message with two symbols is "ss". These types can be mixed and matched in any way. + */ +HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt); + +/** + * Returns a basic string representation of the message. + * The character array MUST be deallocated by the caller. + */ +HV_EXPORT char *hv_msg_toString(const HvMessage *const m); + +/** Copy a message onto the stack. The message persists. */ +HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m); + +/** Free a copied message. */ +HV_EXPORT void hv_msg_free(HvMessage *m); + +#endif // _HEAVY_MESSAGE_H_ + + + +#if !HV_MSVC +#pragma mark - Heavy Patch +#endif + +#ifndef _HEAVY_BBB_H_ +#define _HEAVY_BBB_H_ + +typedef struct Hv_bbb Hv_bbb; + +/** + * Creates a new patch instance. + * Sample rate should be positive and in Hertz. + */ +HV_EXPORT Hv_bbb *hv_bbb_new(double sampleRate); + +/** + * Creates a new patch instance. + * Sample rate should be positive and in Hertz. + * Pool size is in kilobytes, and determines the maximum amount of memory + * allocated to messages at any time. By default this is 10. + */ +HV_EXPORT Hv_bbb *hv_bbb_new_with_pool(double sampleRate, int poolKb); + +/** Frees a patch instance. */ +HV_EXPORT void hv_bbb_free(Hv_bbb *c); + +/** Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays. */ +HV_EXPORT int hv_bbb_process(Hv_bbb *c, float **const inputBuffers, float **const outputBuffers, int n4); + +/** Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels. */ +HV_EXPORT int hv_bbb_process_inline(Hv_bbb *c, float *const inputBuffers, float *const outputBuffers, int n4); + +/** Processes one block of samples for a patch instance. The buffer format is an interleaved short array of channels. */ +HV_EXPORT int hv_bbb_process_inline_short(Hv_bbb *c, short *const inputBuffers, short *const outputBuffers, int n4); +#endif // _HEAVY_BBB_H_ + + + +#if !HV_MSVC +#pragma mark - Heavy Common +#endif + +#ifndef _HEAVY_COMMON_H_ +#define _HEAVY_COMMON_H_ + +typedef void Heavy; + +/** Returns the sample rate with which this patch has been configured. */ +HV_EXPORT double hv_getSampleRate(Heavy *c); + +/** Returns the number of input channels with which this patch has been configured. */ +HV_EXPORT int hv_getNumInputChannels(Heavy *c); + +/** Returns the number of output channels with which this patch has been configured. */ +HV_EXPORT int hv_getNumOutputChannels(Heavy *c); + +/** Set the print hook. The function is called whenever a message is sent to a print object. */ +HV_EXPORT void hv_setPrintHook(Heavy *c, + void (*f)(double timestamp, const char *printName, const char *message, void *userData)); + +/** + * Set the send hook. The function is called whenever a message is sent to any send object. + * Messages returned by this function should NEVER be freed. If the message must persist, call + * hv_msg_copy() first. + */ +HV_EXPORT void hv_setSendHook(Heavy *c, void (*f)(double timestamp, const char *receiverName, const HvMessage *const m, void *userData)); + +HV_EXPORT void hv_vscheduleMessageForReceiver( + Heavy *c, const char *receiverName, double delayMs, const char *format, ...); + +HV_EXPORT void hv_scheduleMessageForReceiver(Heavy *c, const char *receiverName, double delayMs, HvMessage *m); + +/** Cancels a previously scheduled message. */ +HV_EXPORT void hv_cancelMessage(Heavy *c, HvMessage *m); + +/** Returns a table object given its name. NULL if no table with that name exists. */ +HV_EXPORT HvTable *hv_getTableForName(Heavy *c, const char *tableName); + +/** Returns the current patch time in milliseconds. */ +HV_EXPORT double hv_getCurrentTime(Heavy *c); + +/** Sets a user-definable value. This value is never manipulated by Heavy. */ +HV_EXPORT void hv_setUserData(Heavy *c, void *userData); + +/** Returns the user-defined data. */ +HV_EXPORT void *hv_getUserData(Heavy *c); + +/** Define the base path of the patch. Used as the root path to locate assets. */ +HV_EXPORT void hv_setBasePath(Heavy *c, const char *basePath); + +/** Returns the read-only user-assigned name of this patch. */ +HV_EXPORT const char *hv_getName(Heavy *c); + +#endif // _HEAVY_COMMON_H_ + +#ifdef __cplusplus +} // extern "C" +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvBase.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvBase.h" + +void ctx_setBasePath(HvBase *const _c, const char *basePath) { + hv_free(_c->basePath); + if (basePath != NULL) { + hv_size_t len = (hv_size_t) hv_strlen(basePath); + _c->basePath = (char *) hv_malloc((len+1)*sizeof(char)); + hv_strncpy(_c->basePath, basePath, len); + } +} + +void ctx_cancelMessage(HvBase *_c, HvMessage *m, void (*sendMessage)(HvBase *, int, const HvMessage *)) { + mq_removeMessage(&_c->mq, m, sendMessage); +} + +void ctx_scheduleMessageForReceiverV(HvBase *const _c, const char *name, + const hv_uint32_t timestamp, const char *format, ...) { + va_list ap; + va_start(ap, format); + + const int numElem = (int) hv_strlen(format); + HvMessage *m = HV_MESSAGE_ON_STACK(numElem); + msg_init(m, numElem, timestamp); + for (int i = 0; i < numElem; i++) { + switch (format[i]) { + case 'b': msg_setBang(m,i); break; + case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; + case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; + default: break; + } + } + _c->f_scheduleMessageForReceiver(_c, name, m); + + va_end(ap); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvBase.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_BASE_H_ +#define _HEAVY_BASE_H_ + +#include "MessageQueue.h" +#include "Utils.h" + +#define Base(_x) ((HvBase *) _x) + +typedef struct HvBase { + int numInputChannels; + int numOutputChannels; + double sampleRate; + hv_uint32_t blockStartTimestamp; + unsigned int numBytes; // the total number of bytes allocated for this patch + void (*f_scheduleMessageForReceiver)(struct HvBase *const, const char *, HvMessage *); + struct HvTable *(*f_getTableForHash)(struct HvBase *const, hv_uint32_t); + MessageQueue mq; + void (*printHook)(double, const char *, const char *, void *); + void (*sendHook)(double, const char *, const HvMessage *const, void *); + char *basePath; + void *userData; + const char *name; +} HvBase; + +/** + * Schedule a message in the message queue according to its timestamp. + * The copy of the message added to the queue is returned. + */ +static inline HvMessage *ctx_scheduleMessage(HvBase *_c, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *), int outletIndex) { + return mq_addMessageByTimestamp(&_c->mq, (HvMessage *) m, outletIndex, sendMessage); +} + +static inline void ctx_scheduleMessageForReceiver(HvBase *const _c, + const char *name, HvMessage *m) { + _c->f_scheduleMessageForReceiver(_c, name, m); +} + +void ctx_scheduleMessageForReceiverV(HvBase *const _c, const char *name, + const hv_uint32_t timestamp, const char *format, ...); + +void ctx_cancelMessage(HvBase *_c, HvMessage *m, + void (*sendMessage)(HvBase *, int, const HvMessage *)); + +static inline int ctx_millisecondsToSamples(HvBase *_c, float timeInMs) { + return (int) (timeInMs * _c->sampleRate / 1000.0); +} + +static inline double ctx_samplesToMilliseconds(HvBase *_c, int samples) { + return 1000.0 * samples / _c->sampleRate; +} + +static inline double ctx_getSampleRate(HvBase *_c) { + return _c->sampleRate; +} + +static inline int ctx_getNumInputChannels(HvBase *_c) { + return _c->numInputChannels; +} + +static inline int ctx_getNumOutputChannels(HvBase *_c) { + return _c->numOutputChannels; +} + +static inline const char *ctx_getName(HvBase *_c) { + return _c->name; +} + +/** Returns the first sample of the block. */ +static inline hv_uint32_t ctx_getBlockStartTimestamp(HvBase *_c) { + return _c->blockStartTimestamp; +} + +static inline void ctx_setPrintHook(HvBase *const _c, void (*f)(double, + const char *, const char *, void *)) { + _c->printHook = f; +} + +static inline void ctx_setSendHook(HvBase *const _c, void (*f)(double, const char *, const HvMessage *const, void *)) { + _c->sendHook = f; +} + +static inline void *ctx_getUserData(HvBase *const _c) { + return _c->userData; +} + +static inline void ctx_setUserData(HvBase *const _c, void *userData) { + _c->userData = userData; +} + +void ctx_setBasePath(HvBase *const _c, const char *basePath); + +static inline const char *ctx_getBasePath(HvBase *const _c) { + return _c->basePath; +} + +static inline struct HvTable *ctx_getTableForHash(HvBase *const _c, hv_uint32_t h) { + return _c->f_getTableForHash(_c, h); +} + +static inline struct HvTable *ctx_getTableForName(HvBase *const _c, const char *tableName) { + return ctx_getTableForHash(_c, msg_symbolToHash(tableName)); +} + +/** Returns the total number of bytes allocated for this patch. */ +static inline unsigned int ctx_getNumBytes(HvBase *_c) { + return _c->numBytes; +} + +#endif // _HEAVY_BASE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvContext_bbb.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,339 @@ + +/** + * Copyright (c) 2014,2015 Enzien Audio, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or + * sublicense copies of the Software, strictly on a non-commercial basis, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * DO NOT MODIFY. THIS CODE IS MACHINE GENERATED BY THE SECTION6 HEAVY COMPILER. + */ + +/* + * System Includes + */ + +#include <assert.h> +#include <math.h> +#include <string.h> +#include <stdarg.h> +#include "HvContext_bbb.h" +#include "HeavyMath.h" + + +/* + * Function Declarations + */ +static void cBinop_62MLs_sendMessage(HvBase *, int, const HvMessage *const); +static void cUnop_Rm4T9_sendMessage(HvBase *, int, const HvMessage *const); +static void cRandom_Uxs9y_sendMessage(HvBase *, int, const HvMessage *const); +static void cLoadbang_XJMP6_sendMessage(HvBase *, int, const HvMessage *const); +static void cMsg_eMw6t_sendMessage(HvBase *, int, const HvMessage *const); +static void cBinop_vHnCM_sendMessage(HvBase *, int, const HvMessage *const); +static void cBinop_PmuD1_sendMessage(HvBase *, int, const HvMessage *const); +static void cBinop_lT4qw_sendMessage(HvBase *, int, const HvMessage *const); +static void cBinop_vpZDi_sendMessage(HvBase *, int, const HvMessage *const); +static void cMsg_zpcIL_sendMessage(HvBase *, int, const HvMessage *const); +static void cMsg_pfnj7_sendMessage(HvBase *, int, const HvMessage *const); +static void cSystem_lJZJR_sendMessage(HvBase *, int, const HvMessage *const); +static void cVar_cPxQc_sendMessage(HvBase *, int, const HvMessage *const); +static void cBinop_1u9M5_sendMessage(HvBase *, int, const HvMessage *const); +static void cLoadbang_AXnu9_sendMessage(HvBase *, int, const HvMessage *const); + + + +/* + * Static Helper Functions + */ + +static void ctx_intern_scheduleMessageForReceiver( + HvBase *const _c, const char *name, HvMessage *m) { + switch (msg_symbolToHash(name)) { + default: return; + } +} + +static struct HvTable *ctx_intern_getTableForHash(HvBase *const _c, hv_uint32_t h) { + switch (h) { + default: return NULL; + } +} + + + +/* + * Context Include and Implementatons + */ + +Hv_bbb *hv_bbb_new_with_pool(double sampleRate, int poolKb) { + hv_assert(sampleRate > 0.0); // can't initialise with sampling rate of 0 + hv_assert(poolKb >= 1); // a message pool of some reasonable size is always needed + Hv_bbb *const _c = (Hv_bbb *) hv_malloc(sizeof(Hv_bbb)); + + Base(_c)->numInputChannels = 0; + Base(_c)->numOutputChannels = 2; + Base(_c)->sampleRate = sampleRate; + Base(_c)->blockStartTimestamp = 0; + Base(_c)->f_scheduleMessageForReceiver = &ctx_intern_scheduleMessageForReceiver; + Base(_c)->f_getTableForHash = &ctx_intern_getTableForHash; + mq_initWithPoolSize(&Base(_c)->mq, poolKb); + Base(_c)->basePath = NULL; + Base(_c)->printHook = NULL; + Base(_c)->sendHook = NULL; + Base(_c)->userData = NULL; + Base(_c)->name = "bbb"; + + Base(_c)->numBytes = sizeof(Hv_bbb); + Base(_c)->numBytes += sVari_init(&_c->sVari_ecpIx, 0, 0, false); + Base(_c)->numBytes += sVarf_init(&_c->sVarf_VF9rD, 0.0f, 0.0f, false); + Base(_c)->numBytes += sVarf_init(&_c->sVarf_0bFmM, 0.0f, 0.0f, false); + Base(_c)->numBytes += sRPole_init(&_c->sRPole_WxgWS); + Base(_c)->numBytes += sPhasor_k_init(&_c->sPhasor_YcHM3, 880.0f, sampleRate); + Base(_c)->numBytes += sDel1_init(&_c->sDel1_FfVih); + Base(_c)->numBytes += sSamphold_init(&_c->sSamphold_hq9sm); + Base(_c)->numBytes += sPhasor_init(&_c->sPhasor_n1TcS, sampleRate); + Base(_c)->numBytes += cBinop_init(&_c->cBinop_62MLs, 8388610.0f); // __mul + Base(_c)->numBytes += cRandom_init(&_c->cRandom_Uxs9y, -1512500956); + Base(_c)->numBytes += cBinop_init(&_c->cBinop_vHnCM, 1.0f); // __min + Base(_c)->numBytes += cBinop_init(&_c->cBinop_PmuD1, 0.0f); // __max + Base(_c)->numBytes += cBinop_init(&_c->cBinop_lT4qw, 0.0f); // __mul + Base(_c)->numBytes += cVar_init_f(&_c->cVar_cPxQc, 1.0f); + + // loadbang + ctx_scheduleMessage(Base(_c), msg_initWithBang(HV_MESSAGE_ON_STACK(1), 0), &cLoadbang_AXnu9_sendMessage, 0); + ctx_scheduleMessage(Base(_c), msg_initWithBang(HV_MESSAGE_ON_STACK(1), 0), &cLoadbang_XJMP6_sendMessage, 0); + + return _c; +} + +Hv_bbb *hv_bbb_new(double sampleRate) { + return hv_bbb_new_with_pool(sampleRate, 10); // default to 10KB MessagePool +} + +void hv_bbb_free(Hv_bbb *_c) { + + hv_free(Base(_c)->basePath); + mq_free(&Base(_c)->mq); // free queue after all objects have been freed, messages may be cancelled + + hv_free(_c); +} + + + +/* + * Static Function Implementation + */ +static void cBinop_62MLs_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cUnop_onMessage(_c, HV_UNOP_FLOOR, m, &cUnop_Rm4T9_sendMessage); +} + +static void cUnop_Rm4T9_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cMsg_eMw6t_sendMessage(_c, 0, m); +} + +static void cRandom_Uxs9y_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cBinop_onMessage(_c, &Context(_c)->cBinop_62MLs, HV_BINOP_MULTIPLY, 0, m, &cBinop_62MLs_sendMessage); +} + +static void cLoadbang_XJMP6_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cRandom_onMessage(_c, &Context(_c)->cRandom_Uxs9y, 0, m, &cRandom_Uxs9y_sendMessage); +} + +static void cMsg_eMw6t_sendMessage(HvBase *_c, int letIn, const HvMessage *const n) { + HvMessage *m = NULL; + m = HV_MESSAGE_ON_STACK(2); + msg_init(m, 2, msg_getTimestamp(n)); + msg_setElementToFrom(m, 0, n, 0); + msg_setFloat(m, 1, 1.0f); + sVari_onMessage(_c, &Context(_c)->sVari_ecpIx, m); +} + +static void cBinop_vHnCM_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cBinop_onMessage(_c, &Context(_c)->cBinop_PmuD1, HV_BINOP_MAX, 0, m, &cBinop_PmuD1_sendMessage); +} + +static void cBinop_PmuD1_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cBinop_k_onMessage(_c, NULL, HV_BINOP_SUBTRACT, 1.0f, 0, m, &cBinop_1u9M5_sendMessage); + sVarf_onMessage(_c, &Context(_c)->sVarf_VF9rD, m); +} + +static void cBinop_lT4qw_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cBinop_onMessage(_c, &Context(_c)->cBinop_vHnCM, HV_BINOP_MIN, 0, m, &cBinop_vHnCM_sendMessage); +} + +static void cBinop_vpZDi_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cBinop_onMessage(_c, &Context(_c)->cBinop_lT4qw, HV_BINOP_MULTIPLY, 1, m, &cBinop_lT4qw_sendMessage); +} + +static void cMsg_zpcIL_sendMessage(HvBase *_c, int letIn, const HvMessage *const n) { + HvMessage *m = NULL; + m = HV_MESSAGE_ON_STACK(2); + msg_init(m, 2, msg_getTimestamp(n)); + msg_setFloat(m, 0, 6.28319f); + msg_setElementToFrom(m, 1, n, 0); + cBinop_k_onMessage(_c, NULL, HV_BINOP_DIVIDE, 0.0f, 0, m, &cBinop_vpZDi_sendMessage); +} + +static void cMsg_pfnj7_sendMessage(HvBase *_c, int letIn, const HvMessage *const n) { + HvMessage *m = NULL; + m = HV_MESSAGE_ON_STACK(1); + msg_init(m, 1, msg_getTimestamp(n)); + msg_setSymbol(m, 0, "samplerate"); + cSystem_onMessage(_c, NULL, 0, m, &cSystem_lJZJR_sendMessage); +} + +static void cSystem_lJZJR_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cMsg_zpcIL_sendMessage(_c, 0, m); +} + +static void cVar_cPxQc_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cBinop_onMessage(_c, &Context(_c)->cBinop_lT4qw, HV_BINOP_MULTIPLY, 0, m, &cBinop_lT4qw_sendMessage); +} + +static void cBinop_1u9M5_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + sVarf_onMessage(_c, &Context(_c)->sVarf_0bFmM, m); +} + +static void cLoadbang_AXnu9_sendMessage(HvBase *_c, int letIn, const HvMessage *const m) { + cMsg_pfnj7_sendMessage(_c, 0, m); + cVar_onMessage(_c, &Context(_c)->cVar_cPxQc, 0, m, &cVar_cPxQc_sendMessage); +} + + + + +/* + * Context Process Implementation + */ + +int hv_bbb_process(Hv_bbb *const _c, float **const inputBuffers, float **const outputBuffers, int nx) { + const int n4 = nx & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD + + // temporary signal vars + hv_bufferf_t Bf0, Bf1, Bf2, Bf3, Bf4; + hv_bufferi_t Bi0, Bi1; + + // input and output vars + hv_bufferf_t O0, O1; + + // declare and init the zero buffer + hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO)); + + hv_uint32_t nextBlock = Base(_c)->blockStartTimestamp; + for (int n = 0; n < n4; n += HV_N_SIMD) { + + // process all of the messages for this block + nextBlock += HV_N_SIMD; + while (mq_hasMessageBefore(&Base(_c)->mq, nextBlock)) { + MessageNode *const node = mq_peek(&Base(_c)->mq); + node->sendMessage(Base(_c), node->let, node->m); + mq_pop(&Base(_c)->mq); + } + + + + // zero output buffers + __hv_zero_f(VOf(O0)); + __hv_zero_f(VOf(O1)); + + // process all signal functions + __hv_var_i(&_c->sVari_ecpIx, VOi(Bi0)); + __hv_var_k_i(VOi(Bi1), 16807, 16807, 16807, 16807, 16807, 16807, 16807, 16807, 0); + __hv_mul_i(VIi(Bi0), VIi(Bi1), VOi(Bi1)); + __hv_cast_if(VIi(Bi1), VOf(Bf0)); + __hv_var_k_f(VOf(Bf1), 4.65661e-10f, 4.65661e-10f, 4.65661e-10f, 4.65661e-10f, 4.65661e-10f, 4.65661e-10f, 4.65661e-10f, 4.65661e-10f, 0); + __hv_mul_f(VIf(Bf0), VIf(Bf1), VOf(Bf1)); + sVarseti_process(&_c->sVari_ecpIx, VIi(Bi1)); + __hv_var_f(&_c->sVarf_VF9rD, VOf(Bf0)); + __hv_mul_f(VIf(Bf1), VIf(Bf0), VOf(Bf0)); + __hv_var_f(&_c->sVarf_0bFmM, VOf(Bf1)); + __hv_rpole_f(&_c->sRPole_WxgWS, VIf(Bf0), VIf(Bf1), VOf(Bf1)); + __hv_var_k_f(VOf(Bf0), 1000000.0f, 1000000.0f, 1000000.0f, 1000000.0f, 1000000.0f, 1000000.0f, 1000000.0f, 1000000.0f, 0); + __hv_mul_f(VIf(Bf1), VIf(Bf0), VOf(Bf0)); + __hv_phasor_k_f(&_c->sPhasor_YcHM3, VOf(Bf1)); + __hv_del1_f(&_c->sDel1_FfVih, VIf(Bf1), VOf(Bf2)); + __hv_lt_f(VIf(Bf1), VIf(Bf2), VOf(Bf2)); + __hv_samphold_f(&_c->sSamphold_hq9sm, VIf(Bf0), VIf(Bf2), VOf(Bf2)); + __hv_phasor_f(&_c->sPhasor_n1TcS, VIf(Bf2), VOf(Bf2)); + __hv_var_k_f(VOf(Bf0), 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0); + __hv_sub_f(VIf(Bf2), VIf(Bf0), VOf(Bf0)); + __hv_abs_f(VIf(Bf0), VOf(Bf0)); + __hv_var_k_f(VOf(Bf2), 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0); + __hv_sub_f(VIf(Bf0), VIf(Bf2), VOf(Bf2)); + __hv_var_k_f(VOf(Bf0), 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 6.28319f, 0); + __hv_mul_f(VIf(Bf2), VIf(Bf0), VOf(Bf0)); + __hv_mul_f(VIf(Bf0), VIf(Bf0), VOf(Bf2)); + __hv_mul_f(VIf(Bf0), VIf(Bf2), VOf(Bf1)); + __hv_mul_f(VIf(Bf1), VIf(Bf2), VOf(Bf2)); + __hv_var_k_f(VOf(Bf3), 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0.00784314f, 0); + __hv_var_k_f(VOf(Bf4), 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0.166667f, 0); + __hv_mul_f(VIf(Bf1), VIf(Bf4), VOf(Bf4)); + __hv_sub_f(VIf(Bf0), VIf(Bf4), VOf(Bf4)); + __hv_fma_f(VIf(Bf2), VIf(Bf3), VIf(Bf4), VOf(Bf4)); + __hv_var_k_f(VOf(Bf3), 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0); + __hv_mul_f(VIf(Bf4), VIf(Bf3), VOf(Bf3)); + __hv_add_f(VIf(Bf3), VIf(O0), VOf(O0)); + __hv_add_f(VIf(Bf3), VIf(O1), VOf(O1)); + + // save output vars to output buffer + __hv_store_f(outputBuffers[0]+n, VIf(O0)); + __hv_store_f(outputBuffers[1]+n, VIf(O1)); + } + + Base(_c)->blockStartTimestamp = nextBlock; + + return n4; // return the number of frames processed +} + +int hv_bbb_process_inline(Hv_bbb *c, float *const inputBuffers, float *const outputBuffers, int n4) { + hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD + int i = ctx_getNumInputChannels(Base(c)); + float **bIn = (float **) hv_alloca(i*sizeof(float *)); + while (i--) bIn[i] = inputBuffers+(i*n4); + + i = ctx_getNumOutputChannels(Base(c)); + float **bOut = (float **) hv_alloca(i*sizeof(float *)); + while (i--) bOut[i] = outputBuffers+(i*n4); + + int n = hv_bbb_process(c, bIn, bOut, n4); + return n; +} + +int hv_bbb_process_inline_short(Hv_bbb *c, short *const inputBuffers, short *const outputBuffers, int n4) { + hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD + int numChannels = ctx_getNumInputChannels(Base(c)); + float *bIn = (float *) hv_alloca(numChannels*n4*sizeof(float)); + for (int i = 0; i < numChannels; ++i) { + for (int j = 0; j < n4; ++j) { + bIn[i*n4+j] = ((float) inputBuffers[i+numChannels*j]) * 0.00003051757813f; + } + } + + numChannels = ctx_getNumOutputChannels(Base(c)); + float *bOut = (float *) hv_alloca(numChannels*n4*sizeof(float)); + + int n = hv_bbb_process_inline(c, bIn, bOut, n4); + + for (int i = 0; i < numChannels; ++i) { + for (int j = 0; j < n4; ++j) { + outputBuffers[i+numChannels*j] = (short) (bOut[i*n4+j] * 32767.0f); + } + } + + return n; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvContext_bbb.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,69 @@ + +/** + * Copyright (c) 2014,2015 Enzien Audio, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or + * sublicense copies of the Software, strictly on a non-commercial basis, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * DO NOT MODIFY. THIS CODE IS MACHINE GENERATED BY THE SECTION6 HEAVY COMPILER. + */ + +#ifndef _HEAVYCONTEXT_BBB_H_ +#define _HEAVYCONTEXT_BBB_H_ + +#include "HvBase.h" + +#define Context(_x) ((Hv_bbb *) (_x)) + +// object includes +#include "ControlSystem.h" +#include "SignalVar.h" +#include "SignalSamphold.h" +#include "HeavyMath.h" +#include "ControlBinop.h" +#include "ControlVar.h" +#include "ControlRandom.h" +#include "SignalDel1.h" +#include "SignalPhasor.h" +#include "ControlUnop.h" +#include "SignalRPole.h" + +typedef struct Hv_bbb { + HvBase base; + + // objects + SignalVari sVari_ecpIx; + SignalVarf sVarf_VF9rD; + SignalVarf sVarf_0bFmM; + SignalRPole sRPole_WxgWS; + SignalPhasor sPhasor_YcHM3; + SignalDel1 sDel1_FfVih; + SignalSamphold sSamphold_hq9sm; + SignalPhasor sPhasor_n1TcS; + ControlBinop cBinop_62MLs; + ControlRandom cRandom_Uxs9y; + ControlBinop cBinop_vHnCM; + ControlBinop cBinop_PmuD1; + ControlBinop cBinop_lT4qw; + ControlBinop cBinop_vpZDi; + ControlVar cVar_cPxQc; + ControlBinop cBinop_1u9M5; +} Hv_bbb; + +#endif // _HEAVYCONTEXT_BBB_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvMessage.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,335 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvMessage.h" + +HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) { + m->timestamp = timestamp; + m->numElements = (hv_uint16_t) numElements; + m->numBytes = (hv_uint16_t) msg_getByteSize(numElements); + return m; +} + +HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setFloat(m, 0, f); + return m; +} + +HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setBang(m, 0); + return m; +} + +HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, char *s) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setSymbol(m, 0, s); + return m; +} + +HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) { + m->timestamp = timestamp; + m->numElements = 1; + m->numBytes = sizeof(HvMessage); + msg_setHash(m, 0, h); + return m; +} + +HvMessage *msg_initV(HvMessage *const m, const hv_uint32_t timestamp, const char *format, ...) { + va_list ap; + va_start(ap, format); + + const int numElem = (int) hv_strlen(format); + msg_init(m, numElem, timestamp); + for (int i = 0; i < numElem; i++) { + switch (format[i]) { + case 'b': msg_setBang(m,i); break; + case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; + case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; + case 'h': // hash not supported + default: break; + } + } + va_end(ap); + + return m; +} + +hv_size_t msg_getNumHeapBytes(const HvMessage *m) { + // get the size of all symbol elements + hv_size_t rsizeofsym = 0; + for (int i = 0; i < msg_getNumElements(m); ++i) { + if (msg_isSymbol(m,i)) { + rsizeofsym += (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // +1 to allow for trailing '\0' + } + } + + // the total byte size on the heap + return (msg_getByteSize(msg_getNumElements(m)) + rsizeofsym); +} + +void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) { + HvMessage *r = (HvMessage *) buffer; + + // assert that the message is not already larger than the length of the buffer + hv_assert(msg_getNumBytes(m) <= len); + + // copy the basic message to the buffer + hv_memcpy(r, m, msg_getNumBytes(m)); + + hv_size_t len_r = msg_getNumBytes(m); + + char *p = buffer + msg_getByteSize(msg_getNumElements(m)); // points to the end of the base message + for (int i = 0; i < msg_getNumElements(m); ++i) { + if (msg_isSymbol(m,i)) { + const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char + hv_assert(len_r + symLen <= len); // stay safe! + hv_strncpy(p, msg_getSymbol(m,i), symLen); + msg_setSymbol(r, i, p); + p += symLen; + len_r += symLen; + } + } + + r->numBytes = (hv_uint16_t) len_r; // update the message size in memory +} + +// the message is serialised such that all symbol elements are placed in order at the end of the buffer +HvMessage *msg_copy(const HvMessage *m) { + const hv_size_t heapSize = msg_getNumHeapBytes(m); + char *r = (char *) hv_malloc(heapSize); + msg_copyToBuffer(m, r, heapSize); + return (HvMessage *) r; +} + +void msg_free(HvMessage *m) { + hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message +} + +bool msg_hasFormat(const HvMessage *m, const char *fmt) { + if (fmt == NULL) return false; + if (msg_getNumElements(m) != hv_strlen(fmt)) return false; + for (int i = 0; i < msg_getNumElements(m); i++) { + switch (fmt[i]) { + case 'b': if (!msg_isBang(m, i)) return false; break; + case 'f': if (!msg_isFloat(m, i)) return false; break; + case 's': if (!msg_isSymbol(m, i)) return false; break; + case 'h': if (!msg_isHash(m, i)) return false; break; + default: return false; + } + } + return true; +} + +bool msg_compareSymbol(const HvMessage *m, int i, const char *s) { + switch (msg_getType(m,i)) { + case SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s); + case HASH: return (msg_getHash(m,i) == msg_symbolToHash(s)); + default: return false; + } +} + +bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) { + if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) { + if (msg_getType(m, i_m) == msg_getType(n, i_n)) { + switch (msg_getType(m, i_m)) { + case BANG: return true; + case FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n)); + case SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n)); + case HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n); + default: break; + } + } + } + return false; +} + +void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) { + switch (msg_getType(m, i_m)) { + case BANG: msg_setBang(n, i_n); break; + case FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break; + case SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break; + case HASH: msg_setHash(n, i_n, msg_getHash(m, i_m)); + default: break; + } +} + +hv_uint32_t msg_symbolToHash(const char *s) { + // this hash is based MurmurHash2 + // http://en.wikipedia.org/wiki/MurmurHash + // https://sites.google.com/site/murmurhash/ + static const unsigned int n = 0x5bd1e995; + static const int r = 24; + + int len = (int) hv_strlen(s); + hv_uint32_t x = (hv_uint32_t) (len); // seed (0) ^ len + + while (len >= 4) { + hv_uint32_t k = *((hv_uint32_t *)s); + k *= n; + k ^= k >> r; + k *= n; + x *= n; + x ^= k; + s += 4; len -= 4; + } + + switch(len) { + case 3: x ^= s[2] << 16; + case 2: x ^= s[1] << 8; + case 1: x ^= s[0]; x *= n; + default: break; + } + + x ^= x >> 13; + x *= n; + x ^= x >> 15; + + return x; +} + +hv_uint32_t msg_getHash(const HvMessage *const m, int i) { + hv_assert(i < msg_getNumElements(m)); // invalid index + switch (msg_getType(m,i)) { + case BANG: return 0xFFFFFFFF; + case FLOAT: { + float f = msg_getFloat(m,i); + return *((hv_uint32_t *) &f); + } + case SYMBOL: return msg_symbolToHash(msg_getSymbol(m,i)); + case HASH: return (&(m->elem)+i)->data.h; + default: return 0; + } +} + +char *msg_toString(const HvMessage *m) { + hv_assert(msg_getNumElements(m) > 0); + int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int)); + int size = 0; // the total length of our final buffer + + // loop through every element in our list of atoms + // first loop figures out how long our buffer should be + for (int i = 0; i < msg_getNumElements(m); i++) { + // length of our string is each atom plus a space, or \0 on the end + switch (msg_getType(m, i)) { + case BANG: len[i] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break; + case FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break; + case SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break; + case HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; break; + default: break; + } + size += len[i]; + } + + hv_assert(size > 0); + + // now we do the piecewise concatenation into our final string + // the final buffer we will pass back after concatenating all strings - user should free it + char *finalString = (char *) hv_malloc(size*sizeof(char)); + int pos = 0; + for (int i = 0; i < msg_getNumElements(m); i++) { + // put a string representation of each atom into the final string + switch (msg_getType(m, i)) { + case BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break; + case FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break; + case SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break; + case HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break; + default: break; + } + pos += len[i]; + finalString[pos-1] = 32; // ASCII space + } + finalString[size-1] = '\0'; // ensure that the string is null terminated + return finalString; +} + +/* + * TODO(mhroth): unnecessary for now +bool msg_resolveDollarArguments(HvMessage *m, HvMessage *n, int z, char *buf, hv_size_t len, const char *args, ...) { + va_list ap; + va_start(ap, args); + + hv_memset(buf, 0, len); // clear the buffer + hv_size_t j = 0; // position in buffer + const hv_size_t numArgs = hv_strlen(args); // the number of arguments + + // if there is only one argument then the result has the chance of being a number, otherwise no + bool isNumber = (numArgs == 1); + + for (hv_size_t i = 0; i < numArgs; ++i) { + switch (args[i]) { + case 'i': { // a message index + const int index = (int) va_arg(ap, int); + if (index < 0) { + // $0 always resolve to "0" + const hv_size_t x = 1; + if (x < len-j) { // always < in order to allow for trailing \0 + j += snprintf(buf+j, len-j, "0"); + } + } else { + switch (msg_getType(m, index)) { + default: + case BANG: break; // this case should never happen + case FLOAT: { + const hv_size_t x = snprintf(NULL, 0, "%g", msg_getFloat(m,index)); + if (x < len-j) { // ensure that the buffer is big enough + j += snprintf(buf+j, len-j, "%g", msg_getFloat(m,index)); + } + break; + } + case SYMBOL: { + const hv_size_t x = snprintf(NULL, 0, "%s", msg_getSymbol(m,index)); + if (x < len-j) { + j += snprintf(buf+j, len-j, "%s", msg_getSymbol(m,index)); + isNumber = false; + } + break; + } + } + } + break; + } + case 's': { // a string + const char *s = (char *) va_arg(ap, char *); + const hv_size_t x = snprintf(NULL, 0, "%s", s); + if (x <= len-j) { + j += snprintf(buf+j, len-j, "%s", s); + isNumber = false; + } + break; + } + default: break; + } + } + + if (isNumber) { + msg_setFloat(n,z,(float) atof(buf)); + } else { + msg_setSymbol(n,z,buf); + } + + va_end(ap); + + return !isNumber; +} +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvMessage.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_MESSAGE_H_ +#define _HEAVY_MESSAGE_H_ + +#include "Utils.h" + +typedef enum ElementType { + BANG, + FLOAT, + SYMBOL, + HASH +} ElementType; + +typedef struct Element { + ElementType type; + union { + float f; // float + char *s; // symbol + hv_uint32_t h; // hash + } data; +} Element; + +typedef struct HvMessage { + hv_uint32_t timestamp; // the sample at which this message should be processed + hv_uint16_t numElements; + hv_uint16_t numBytes; // the number of bytes that this message occupies in memory + Element elem; +} HvMessage; + +#define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getByteSize(_x)) + +/** Returns the total length in bytes of this message for a given number of elements. */ +static inline hv_size_t msg_getByteSize(hv_size_t numElements) { + hv_assert(numElements > 0); + return sizeof(HvMessage) + ((numElements-1) * sizeof(Element)); +} + +HvMessage *msg_copy(const HvMessage *m); + +/** Returns the number of bytes that this message would occupy on the heap. */ +hv_size_t msg_getNumHeapBytes(const HvMessage *m); + +/** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */ +void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len); + +void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM); + +/** Frees a message on the heap. Does nothing if argument is NULL. */ +void msg_free(HvMessage *m); + +HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp); + +HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f); + +HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp); + +HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, char *s); + +HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h); + +HvMessage *msg_initV(HvMessage *const m, const hv_uint32_t timestamp, const char *format, ...); + +static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) { + return m->timestamp; +} + +static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) { + m->timestamp = timestamp; +} + +static inline int msg_getNumElements(const HvMessage *m) { + return (int) m->numElements; +} + +/** Returns the number of bytes this message in memory. */ +static inline hv_size_t msg_getNumBytes(const HvMessage *m) { + return m->numBytes; +} + +static inline ElementType msg_getType(const HvMessage *m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + return (&(m->elem)+index)->type; +} + +static inline void msg_setBang(HvMessage *m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = BANG; + (&(m->elem)+index)->data.s = NULL; +} + +static inline bool msg_isBang(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == BANG) : false; +} + +static inline void msg_setFloat(HvMessage *m, int index, float f) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = FLOAT; + (&(m->elem)+index)->data.f = f; +} + +static inline float msg_getFloat(const HvMessage *const m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + return (&(m->elem)+index)->data.f; +} + +static inline bool msg_isFloat(const HvMessage *const m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == FLOAT) : false; +} + +static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = HASH; + (&(m->elem)+index)->data.h = h; +} + +static inline bool msg_isHash(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HASH) : false; +} + +/** Returns true if the element is a hash or symbol. False otherwise. */ +static inline bool msg_isHashLike(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HASH) || (msg_getType(m, index) == SYMBOL)) : false; +} + +/** Returns a 32-bit hash of the given string. */ +hv_uint32_t msg_symbolToHash(const char *s); + +/** Returns a 32-bit hash of the given element. */ +hv_uint32_t msg_getHash(const HvMessage *const m, int i); + +static inline void msg_setSymbol(HvMessage *m, int index, char *s) { + hv_assert(index < msg_getNumElements(m)); // invalid index + (&(m->elem)+index)->type = SYMBOL; + (&(m->elem)+index)->data.s = s; +} + +static inline char *msg_getSymbol(const HvMessage *m, int index) { + hv_assert(index < msg_getNumElements(m)); // invalid index + return (&(m->elem)+index)->data.s; +} + +static inline bool msg_isSymbol(const HvMessage *m, int index) { + return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == SYMBOL) : false; +} + +bool msg_compareSymbol(const HvMessage *m, int i, const char *s); + +/** Returns 1 if the element i_m of message m is equal to element i_n of message n. */ +bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n); + +bool msg_hasFormat(const HvMessage *m, const char *fmt); + +/** + * Create a string representation of the message. Suitable for use by the print object. + * The resulting string must be freed by the caller. + */ +char *msg_toString(const HvMessage *msg); + +/** + * Resolves any number of dollar arguments and generates a string based on the arguments. + * @param m The message from which to take values + * @param n The message to fill in + * @param z The element index to resolve + * @param buf The scratch (i.e. resolution) buffer + * @param len The length of the scratch buffer + * @param args A string of 'i' and 's' chars indicating the type of the arguments, either indicies or strings + * @param varargs The components to resolve, either dollar indicies or strings. + * If the index is negative, the graph id is used + * @return true if the resolution buffer is needed, false otherwise. + */ +// bool msg_resolveDollarArguments(HvMessage *m, HvMessage *n, int z, char *buf, hv_size_t len, const char *args, ...); + +#endif // _HEAVY_MESSAGE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvTable.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "HvTable.h" + +hv_size_t hTable_init(HvTable *o, int length) { + o->length = length; + // true size of the table is always an integer multple of HV_N_SIMD + o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; + // add an extra length for mirroring + o->allocated = o->size + HV_N_SIMD; + o->head = 0; + hv_size_t numBytes = o->allocated * sizeof(float); + o->buffer = (float *) hv_malloc(numBytes); + hv_memset(o->buffer, numBytes); + return numBytes; +} + +hv_size_t hTable_initWithData(HvTable *o, int length, const float *const data) { + o->length = length; + o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; + o->allocated = o->size + HV_N_SIMD; + o->head = 0; + hv_size_t numBytes = o->size * sizeof(float); + o->buffer = (float *) hv_malloc(numBytes); + hv_memset(o->buffer, numBytes); + hv_memcpy(o->buffer, data, length*sizeof(float)); + return numBytes; +} + +hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) { + o->length = length; + o->size = length; + o->allocated = length; + o->buffer = data; + o->head = 0; + return 0; +} + +void hTable_free(HvTable *o) { + hv_free(o->buffer); +} + +int hTable_resize(HvTable *o, hv_uint32_t newLength) { + // TODO(mhroth): update context with memory allocated by table + // NOTE(mhroth): mirrored bytes are not necessarily carried over + const hv_uint32_t oldBytes = (hv_uint32_t) (o->size * sizeof(float)); + const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; + const hv_uint32_t newAllocated = newSize + HV_N_SIMD; + const hv_uint32_t newBytes = (hv_uint32_t) (newAllocated * sizeof(float)); + float *b = (float *) hv_realloc(o->buffer, newBytes); + hv_assert(b != NULL); // error while reallocing! + if (newSize > o->size) hv_clear_buffer(b+o->size, newAllocated-o->size); // clear new parts of the buffer + if (b != o->buffer) { + // the buffer has been reallocated, ensure that it is on a 32-byte boundary + if ((((uintptr_t) (const void *) b) & 0x10) == 0) { + o->buffer = b; + } else { + float *c = (float *) hv_malloc(newBytes); + hv_assert(c != NULL); + hv_clear_buffer(c, newLength); + const hv_size_t min = hv_min_ui(o->size, newLength); + hv_memcpy(c, b, min * sizeof(float)); + hv_free(b); + o->buffer = c; + } + } + o->length = newLength; + o->size = newSize; + o->allocated = newAllocated; + return (int) (newBytes - oldBytes); +} + +void hTable_onMessage(HvBase *_c, HvTable *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)) { + if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) { + hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space + + // send out the new size of the table + HvMessage *n = HV_MESSAGE_ON_STACK(1); + msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o)); + sendMessage(_c, 0, n); + } + + else if (msg_compareSymbol(m,0,"mirror")) { + hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/HvTable.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_TABLE_H_ +#define _HEAVY_TABLE_H_ + +#include "HvBase.h" +#include "HvMessage.h" +#include "Utils.h" + +typedef struct HvTable { + float *buffer; + // the number of values that the table is requested to have + hv_uint32_t length; + + // the number of usable values that the table actually has + // this is always an even multiple of HV_N_SIMD + hv_uint32_t size; + + // Note that the true size of the table is (size + HV_N_SIMD), + // with the trailing values used by the system, e.g. to create a circular + // buffer + hv_uint32_t allocated; + + hv_uint32_t head; // the most recently written point +} HvTable; + +hv_size_t hTable_init(HvTable *o, int length); + +hv_size_t hTable_initWithData(HvTable *o, int length, const float *const data); + +hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data); + +void hTable_free(HvTable *o); + +int hTable_resize(HvTable *o, hv_uint32_t newLength); + +void hTable_onMessage(HvBase *_c, HvTable *o, int letIn, const HvMessage *const m, + void (*sendMessage)(HvBase *, int, const HvMessage *const)); + +static inline float *hTable_getBuffer(HvTable *o) { + return o->buffer; +} + +// the user-requested length of the table (number of floats) +static inline hv_uint32_t hTable_getLength(HvTable *o) { + return o->length; +} + +// the usable length of the table (an even multiple of HV_N_SIMD) +static inline hv_uint32_t hTable_getSize(HvTable *o) { + return o->size; +} + +// the number of floats allocated to this table (usually size + HV_N_SIMD) +static inline hv_uint32_t hTable_getAllocated(HvTable *o) { + return o->allocated; +} + +static inline hv_uint32_t hTable_getHead(HvTable *o) { + return o->head; +} + +static inline void hTable_setHead(HvTable *o, hv_uint32_t head) { + o->head = head; +} + +#endif // _HEAVY_TABLE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/MessagePool.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "MessagePool.h" +#include "HvMessage.h" +#include "Utils.h" + +// the number of bytes reserved at a time from the pool +#define MP_BLOCK_SIZE_BYTES 512 + +#if HV_APPLE +#pragma mark - MessageList +#endif + +typedef struct MessageListNode { + char *p; + struct MessageListNode *next; +} MessageListNode; + +static inline bool ml_hasAvailable(MessagePoolList *ml) { + return (ml->head != NULL); +} + +static char *ml_pop(MessagePoolList *ml) { + MessageListNode *n = ml->head; + ml->head = n->next; + n->next = ml->pool; + ml->pool = n; + char *const p = n->p; + n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer + return p; +} + +/** Push a MessageListNode with the given pointer onto the head of the queue. */ +static void ml_push(MessagePoolList *ml, void *p) { + MessageListNode *n = NULL; + if (ml->pool != NULL) { + // take an empty MessageListNode from the pool + n = ml->pool; + ml->pool = n->next; + } else { + // a MessageListNode is not available, allocate one + n = (MessageListNode *) hv_malloc(sizeof(MessageListNode)); + } + n->p = (char *) p; + n->next = ml->head; + ml->head = n; // push to the front of the queue +} + +static void ml_free(MessagePoolList *ml) { + if (ml != NULL) { + while (ml_hasAvailable(ml)) { + ml_pop(ml); + } + while (ml->pool != NULL) { + MessageListNode *n = ml->pool; + ml->pool = n->next; + hv_free(n); + } + } +} + +#if HV_APPLE +#pragma mark - MessagePool +#endif + +static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) { + return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0); +} + +hv_size_t mp_init(MessagePool *mp, hv_size_t numKB) { + mp->bufferSize = numKB * 1024; + mp->buffer = (char *) hv_malloc(mp->bufferSize); + mp->bufferIndex = 0; + + // initialise all message lists + for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) { + mp->lists[i].head = NULL; + mp->lists[i].pool = NULL; + } + + return mp->bufferSize; +} + +void mp_free(MessagePool *mp) { + hv_free(mp->buffer); + for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) { + ml_free(&mp->lists[i]); + } +} + +void mp_freeMessage(MessagePool *mp, HvMessage *m) { + const hv_size_t b = msg_getNumBytes(m); // the number of bytes that a message occupies in memory + const hv_size_t i = mp_messagelistIndexForSize(b); // the MessagePoolList index in the pool + MessagePoolList *ml = &mp->lists[i]; + const hv_size_t chunkSize = 32 << i; + hv_memset(m, chunkSize); // clear the chunk, just in case + ml_push(ml, m); +} + +HvMessage *mp_addMessage(MessagePool *mp, const HvMessage *m) { + const hv_size_t b = msg_getNumHeapBytes(m); + // determine the message list index to allocate data from based on the msg size + // smallest chunk size is 32 bytes + const hv_size_t i = mp_messagelistIndexForSize(b); + + assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment + MessagePoolList *ml = &mp->lists[i]; + const hv_size_t chunkSize = 32 << i; + + if (ml_hasAvailable(ml)) { + char *buf = ml_pop(ml); + msg_copyToBuffer(m, buf, chunkSize); + return (HvMessage *) buf; + } else { + // if no appropriately sized buffer is immediately available, increase the size of the used buffer + const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES; + hv_assert(newIndex <= mp->bufferSize); // have we have exceeded the buffer size? + + for (hv_size_t i = mp->bufferIndex; i < newIndex; i += chunkSize) { + ml_push(ml, mp->buffer + i); // push new nodes onto the list with chunk pointers + } + mp->bufferIndex = newIndex; + char *buf = ml_pop(ml); + msg_copyToBuffer(m, buf, chunkSize); + return (HvMessage *) buf; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/MessagePool.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MESSAGE_POOL_H_ +#define _MESSAGE_POOL_H_ + +#include "Utils.h" + +struct HvMessage; + +#define MP_NUM_MESSAGE_LISTS 4 + +typedef struct MessagePoolList { + struct MessageListNode *head; // list of currently available blocks + struct MessageListNode *pool; // list of currently used blocks +} MessagePoolList; + +typedef struct MessagePool { + char *buffer; // the buffer of all messages + hv_size_t bufferSize; // in bytes + hv_size_t bufferIndex; // the number of total reserved bytes + + MessagePoolList lists[MP_NUM_MESSAGE_LISTS]; +} MessagePool; + +/** + * The MessagePool is a basic memory management system. It reserves a large block of memory at initialisation + * and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are + * further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a MessagePoolList (MPL). + * An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes + * that point at each subblock (e.g. each 32-byte block of a 512-block chunk). + * + * MessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html + */ + +hv_size_t mp_init(struct MessagePool *mp, hv_size_t numKB); + +void mp_free(struct MessagePool *mp); + +/** + * Adds a message to the pool and returns a pointer to the copy. Returns NULL + * if no space was available in the pool. + */ +struct HvMessage *mp_addMessage(struct MessagePool *mp, const struct HvMessage *m); + +void mp_freeMessage(struct MessagePool *mp, struct HvMessage *m); + +#endif // _MESSAGE_POOL_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/MessageQueue.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "MessageQueue.h" +#include "Utils.h" + +hv_size_t mq_init(MessageQueue *q) { + q->head = NULL; + q->tail = NULL; + q->pool = NULL; + return mp_init(&q->mp, 1); +} + +void mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB) { + q->head = NULL; + q->tail = NULL; + q->pool = NULL; + mp_init(&q->mp, poolSizeKB); +} + +void mq_free(MessageQueue *q) { + mq_clear(q); + while (q->pool != NULL) { + MessageNode *n = q->pool; + q->pool = q->pool->next; + hv_free(n); + } + mp_free(&q->mp); +} + +static MessageNode *mq_getOrCreateNodeFromPool(MessageQueue *q) { + if (q->pool == NULL) { + // if necessary, create a new empty node + q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode)); + q->pool->next = NULL; + } + MessageNode *node = q->pool; + q->pool = q->pool->next; + return node; +} + +int mq_size(MessageQueue *q) { + int size = 0; + MessageNode *n = q->head; + while (n != NULL) { + ++size; + n = n->next; + } + return size; +} + +HvMessage *mq_addMessage(MessageQueue *q, const HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + MessageNode *node = mq_getOrCreateNodeFromPool(q); + node->m = mp_addMessage(&q->mp, m); + node->let = let; + node->sendMessage = sendMessage; + node->prev = NULL; + node->next = NULL; + + if (q->tail != NULL) { + // the list already contains elements + q->tail->next = node; + node->prev = q->tail; + q->tail = node; + } else { + // the list is empty + node->prev = NULL; + q->head = node; + q->tail = node; + } + return mq_node_getMessage(node); +} + +HvMessage *mq_addMessageByTimestamp(MessageQueue *q, HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + if (mq_hasMessage(q)) { + MessageNode *n = mq_getOrCreateNodeFromPool(q); + n->m = mp_addMessage(&q->mp, m); + n->let = let; + n->sendMessage = sendMessage; + + if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) { + // the message occurs before the current head + n->next = q->head; + q->head->prev = n; + n->prev = NULL; + q->head = n; + } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) { + // the message occurs after the current tail + n->next = NULL; + n->prev = q->tail; + q->tail->next = n; + q->tail = n; + } else { + // the message occurs somewhere between the head and tail + MessageNode *node = q->head; + while (node != NULL) { + if (m->timestamp < msg_getTimestamp(node->next->m)) { + MessageNode *r = node->next; + node->next = n; + n->next = r; + n->prev = node; + r->prev = n; + break; + } + node = node->next; + } + } + return n->m; + } else { + // add a message to the head + return mq_addMessage(q, m, let, sendMessage); + } +} + +void mq_pop(MessageQueue *q) { + if (mq_hasMessage(q)) { + MessageNode *n = q->head; + + mp_freeMessage(&q->mp, n->m); + n->m = NULL; + + n->let = 0; + n->sendMessage = NULL; + + q->head = n->next; + if (q->head == NULL) { + q->tail = NULL; + } else { + q->head->prev = NULL; + } + n->next = q->pool; + n->prev = NULL; + q->pool = n; + } +} + +void mq_removeMessage(MessageQueue *q, HvMessage *m, void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + if (mq_hasMessage(q)) { + if (mq_node_getMessage(q->head) == m) { // msg in head node + // only remove the message if sendMessage is the same as the stored one, + // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer + if (sendMessage == NULL || q->head->sendMessage == sendMessage) { + mq_pop(q); + } + } else { + MessageNode *prevNode = q->head; + MessageNode *currNode = q->head->next; + while ((currNode != NULL) && (currNode->m != m)) { + prevNode = currNode; + currNode = currNode->next; + } + if (currNode != NULL) { + if (sendMessage == NULL || currNode->sendMessage == sendMessage) { + mp_freeMessage(&q->mp, m); + currNode->m = NULL; + currNode->let = 0; + currNode->sendMessage = NULL; + if (currNode == q->tail) { // msg in tail node + prevNode->next = NULL; + q->tail = prevNode; + } else { // msg in middle node + prevNode->next = currNode->next; + currNode->next->prev = prevNode; + } + currNode->next = (q->pool == NULL) ? NULL : q->pool; + currNode->prev = NULL; + q->pool = currNode; + } + } + } + } +} + +void mq_clear(MessageQueue *q) { + while (mq_hasMessage(q)) { + mq_pop(q); + } +} + +void mq_clearAfter(MessageQueue *q, const double timestamp) { + MessageNode *n = q->tail; + while (n != NULL && timestamp <= msg_getTimestamp(n->m)) { + // free the node's message + mp_freeMessage(&q->mp, n->m); + n->m = NULL; + n->let = 0; + n->sendMessage = NULL; + + // the tail points at the previous node + q->tail = n->prev; + + // put the node back in the pool + n->next = q->pool; + n->prev = NULL; + if (q->pool != NULL) q->pool->prev = n; + q->pool = n; + + // update the tail node + n = q->tail; + } + + if (q->tail == NULL) q->head = NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/MessageQueue.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MESSAGE_QUEUE_H_ +#define _MESSAGE_QUEUE_H_ + +#include "HvMessage.h" +#include "MessagePool.h" + +struct HvBase; + +typedef struct MessageNode { + struct MessageNode *prev; // doubly linked list + struct MessageNode *next; + HvMessage *m; + void (*sendMessage)(struct HvBase *, int, const HvMessage *); + int let; +} MessageNode; + +/** A doubly linked list containing scheduled messages. */ +typedef struct MessageQueue { + MessageNode *head; // the head of the queue + MessageNode *tail; // the tail of the queue + MessageNode *pool; // the head of the reserve pool + MessagePool mp; +} MessageQueue; + +hv_size_t mq_init(MessageQueue *q); + +void mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB); + +void mq_free(MessageQueue *q); + +int mq_size(MessageQueue *q); + +static inline HvMessage *mq_node_getMessage(MessageNode *n) { + return n->m; +} + +static inline int mq_node_getLet(MessageNode *n) { + return n->let; +} + +static inline bool mq_hasMessage(MessageQueue *q) { + return (q->head != NULL); +} + +// true if there is a message and it occurs before (<) timestamp +static inline bool mq_hasMessageBefore(MessageQueue *const q, const hv_uint32_t timestamp) { + return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp); +} + +static inline MessageNode *mq_peek(MessageQueue *q) { + return q->head; +} + +/** Appends the message to the end of the queue. */ +HvMessage *mq_addMessage(MessageQueue *q, const HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)); + +/** Insert in ascending order the message acccording to its timestamp. */ +HvMessage *mq_addMessageByTimestamp(MessageQueue *q, HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)); + +/** Pop the message at the head of the queue (and free its memory). */ +void mq_pop(MessageQueue *q); + +/** Remove a message from the queue (and free its memory) */ +void mq_removeMessage(MessageQueue *q, HvMessage *m, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)); + +/** Clears (and frees) all messages in the queue. */ +void mq_clear(MessageQueue *q); + +/** Removes all messages occuring at or after the given timestamp. */ +void mq_clearAfter(MessageQueue *q, const double timestamp); + +#endif // _MESSAGE_QUEUE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalDel1.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalDel1.h" + +hv_size_t sDel1_init(SignalDel1 *o) { +#if HV_SIMD_AVX + o->x = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + o->x = _mm_setzero_ps(); +#elif HV_SIMD_NEON + o->x = vdupq_n_f32(0.0f); +#else + o->x = 0.0f; +#endif + return 0; +} + +void sDel1_onMessage(HvBase *_c, SignalDel1 *o, int letIn, const HvMessage *m) { + if (letIn == 2) { + if (msg_compareSymbol(m, 0, "clear")) { +#if HV_SIMD_AVX + o->x = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + o->x = _mm_setzero_ps(); +#elif HV_SIMD_NEON + o->x = vdupq_n_f32(0.0f); +#else + o->x = 0.0f; +#endif + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalDel1.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SIGNAL_DEL1_H_ +#define _SIGNAL_DEL1_H_ + +#include "HvBase.h" + +typedef struct SignalDel1 { + hv_bufferf_t x; +} SignalDel1; + +hv_size_t sDel1_init(SignalDel1 *o); + +void sDel1_onMessage(HvBase *_c, SignalDel1 *o, int letIn, const HvMessage *m); + +static inline void __hv_del1_f(SignalDel1 *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + __m256 x = _mm256_permute_ps(bIn0, _MM_SHUFFLE(2,1,0,3)); // [3 0 1 2 7 4 5 6] + __m256 n = _mm256_permute2f128_ps(o->x,x,0x1); // [h e f g 3 0 1 2] + *bOut = _mm256_blend_ps(x, n, 0x11); // [g 0 1 2 3 4 5 6] + o->x = x; +#elif HV_SIMD_SSE + __m128 n = _mm_blend_ps(o->x, bIn0, 0x7); + *bOut = _mm_shuffle_ps(n, n, _MM_SHUFFLE(2,1,0,3)); + o->x = bIn0; +#elif HV_SIMD_NEON + *bOut = vextq_f32(o->x, bIn0, 3); + o->x = bIn0; +#else + *bOut = o->x; + o->x = bIn0; +#endif +} + +#endif // _SIGNAL_DEL1_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalPhasor.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalPhasor.h" + +// input phase is in the range of [0,1]. It is independent of o->phase. +#if HV_SIMD_AVX +static void sPhasor_updatePhase(SignalPhasor *o, float p) { + o->phase = _mm256_set_ps( + p+1.0f+7.0f*o->step.f2sc, p+1.0f+6.0f*o->step.f2sc, + p+1.0f+5.0f*o->step.f2sc, p+1.0f+4.0f*o->step.f2sc, + p+1.0f+3.0f*o->step.f2sc, p+1.0f+2.0f*o->step.f2sc, + p+1.0f+o->step.f2sc, p+1.0f); + + // ensure that o->phase is still in range [1,2] + o->phase = _mm256_or_ps(_mm256_andnot_ps( + _mm256_set1_ps(-INFINITY), o->phase), _mm256_set1_ps(1.0f)); +#elif HV_SIMD_SSE +static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { + o->phase = _mm_set_epi32(3*o->step.s+p, 2*o->step.s+p, o->step.s+p, p); +#elif HV_SIMD_NEON +static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { + o->phase = (uint32x4_t) {p, o->step.s+p, 2*o->step.s+p, 3*o->step.s+p}; +#else // HV_SIMD_NONE +static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { + o->phase = p; +#endif +} + +static void sPhasor_updateFrequency(SignalPhasor *o, float f, double r) { +#if HV_SIMD_AVX + o->step.f2sc = (float) (f/r); + o->inc = _mm256_set1_ps((float) (8.0f*f/r)); + sPhasor_updatePhase(o, o->phase[0]); +#elif HV_SIMD_SSE + o->step.s = (hv_int32_t) (f*(4294967296.0/r)); + o->inc = _mm_set1_epi32(4*o->step.s); + sPhasor_updatePhase(o, (hv_uint32_t) (o->phase[0] & 0xFFFFFFFFL)); +#elif HV_SIMD_NEON + o->step.s = (hv_int32_t) (f*(4294967296.0/r)); + o->inc = vdupq_n_s32(4*o->step.s); + sPhasor_updatePhase(o, vgetq_lane_u32(o->phase, 0)); +#else // HV_SIMD_NONE + o->step.s = (hv_int32_t) (f*(4294967296.0/r)); + o->inc = o->step.s; + // no need to update phase +#endif +} + +hv_size_t sPhasor_init(SignalPhasor *o, double samplerate) { +#if HV_SIMD_AVX + o->phase = _mm256_set1_ps(1.0f); + o->inc = _mm256_setzero_ps(); + o->step.f2sc = (float) (1.0/samplerate); +#elif HV_SIMD_SSE + o->phase = _mm_setzero_si128(); + o->inc = _mm_setzero_si128(); + o->step.f2sc = (float) (4294967296.0/samplerate); +#elif HV_SIMD_NEON + o->phase = vdupq_n_u32(0); + o->inc = vdupq_n_s32(0); + o->step.f2sc = (float) (4294967296.0/samplerate); +#else // HV_SIMD_NONE + o->phase = 0; + o->inc = 0; + o->step.f2sc = (float) (4294967296.0/samplerate); +#endif + return 0; +} + +void sPhasor_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m) { + if (letIn == 1) { + if (msg_isFloat(m,0)) { + float phase = msg_getFloat(m,0); + while (phase < 0.0f) phase += 1.0f; // wrap phase to [0,1] + while (phase > 1.0f) phase -= 1.0f; +#if HV_SIMD_AVX + sPhasor_updatePhase(o, phase); +#else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE + sPhasor_updatePhase(o, (hv_int32_t) (phase * 4294967296.0)); +#endif + } + } +} + +hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate) { + sPhasor_updateFrequency(o, frequency, samplerate); + sPhasor_updatePhase(o, 0); + return 0; +} + +void sPhasor_k_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m) { + if (msg_isFloat(m,0)) { + switch (letIn) { + case 0: sPhasor_updateFrequency(o, msg_getFloat(m,0), ctx_getSampleRate(_c)); break; + case 1: { + float phase = msg_getFloat(m,0); + while (phase < 0.0f) phase += 1.0f; // wrap phase to [0,1] + while (phase > 1.0f) phase -= 1.0f; +#if HV_SIMD_AVX + sPhasor_updatePhase(o, phase); +#else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE + sPhasor_updatePhase(o, (hv_uint32_t) (phase * 4294967296.0)); +#endif + break; + } + default: break; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalPhasor.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_SIGNAL_PHASOR_H_ +#define _HEAVY_SIGNAL_PHASOR_H_ + +#include "HvBase.h" + +typedef struct SignalPhasor { +#if HV_SIMD_AVX + __m256 phase; // current phase + __m256 inc; // phase increment +#elif HV_SIMD_SSE + __m128i phase; + __m128i inc; +#elif HV_SIMD_NEON + uint32x4_t phase; + int32x4_t inc; +#else // HV_SIMD_NONE + hv_uint32_t phase; + hv_int32_t inc; +#endif + union { + float f2sc; // float to step conversion (used for __phasor~f) + hv_int32_t s; // step value (used for __phasor_k~f) + } step; +} SignalPhasor; + +hv_size_t sPhasor_init(SignalPhasor *o, double samplerate); + +hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate); + +void sPhasor_k_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m); + +void sPhasor_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m); + +static inline void __hv_phasor_f(SignalPhasor *o, hv_bInf_t bIn, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + __m256 p = _mm256_mul_ps(bIn, _mm256_set1_ps(o->step.f2sc)); // a b c d e f g h + + __m256 z = _mm256_setzero_ps(); + + // http://stackoverflow.com/questions/11906814/how-to-rotate-an-sse-avx-vector + __m256 a = _mm256_permute_ps(p, _MM_SHUFFLE(2,1,0,3)); // d a b c h e f g + __m256 b = _mm256_permute2f128_ps(a, a, 0x01); // h e f g d a b c + __m256 c = _mm256_blend_ps(a, b, 0x10); // d a b c d e f g + __m256 d = _mm256_blend_ps(c, z, 0x01); // 0 a b c d e f g + __m256 e = _mm256_add_ps(p, d); // a (a+b) (b+c) (c+d) (d+e) (e+f) (f+g) (g+h) + + __m256 f = _mm256_permute_ps(e, _MM_SHUFFLE(1,0,3,2)); // (b+c) (c+d) a (a+b) (f+g) (g+h) (d+e) (e+f) + __m256 g = _mm256_permute2f128_ps(f, f, 0x01); // (f+g) (g+h) (d+e) (e+f) (b+c) (c+d) a (a+b) + __m256 h = _mm256_blend_ps(f, g, 0x33); // (b+c) (c+d) a (a+b) (b+c) (c+d) (d+e) (e+f) + __m256 i = _mm256_blend_ps(h, z, 0x03); // 0 0 a (a+b) (b+c) (c+d) (d+e) (e+f) + __m256 j = _mm256_add_ps(e, i); // a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) (c+d+e+f) (d+e+f+g) (e+f+g+h) + + __m256 k = _mm256_permute2f128_ps(j, z, 0x02); // 0 0 0 0 a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) + __m256 m = _mm256_add_ps(j, k); // a (a+b) (a+b+c) (a+b+c+d) (a+b+c+d+e) (a+b+c+d+e+f) (a+b+c+d+e+f+g) (a+b+c+d+e+f+g+h) + + __m256 n = _mm256_or_ps(_mm256_andnot_ps( + _mm256_set1_ps(-INFINITY), + _mm256_add_ps(o->phase, m)), + _mm256_set1_ps(1.0f)); + + *bOut = _mm256_sub_ps(n, _mm256_set1_ps(1.0f)); + + __m256 x = _mm256_permute_ps(n, _MM_SHUFFLE(3,3,3,3)); + o->phase = _mm256_permute2f128_ps(x, x, 0x11); +#elif HV_SIMD_SSE + __m128i p = _mm_cvtps_epi32(_mm_mul_ps(bIn, _mm_set1_ps(o->step.f2sc))); // convert frequency to step + p = _mm_add_epi32(p, _mm_slli_si128(p, 4)); // add incremental steps to phase (prefix sum) + p = _mm_add_epi32(p, _mm_slli_si128(p, 8)); // http://stackoverflow.com/questions/10587598/simd-prefix-sum-on-intel-cpu?rq=1 + p = _mm_add_epi32(o->phase, p); + *bOut = _mm_sub_ps(_mm_castsi128_ps( + _mm_or_si128(_mm_srli_epi32(p, 9), + (__m128i) {0x3F8000003F800000L, 0x3F8000003F800000L})), + _mm_set1_ps(1.0f)); + o->phase = _mm_shuffle_epi32(p, _MM_SHUFFLE(3,3,3,3)); +#elif HV_SIMD_NEON + int32x4_t p = vcvtq_s32_f32(vmulq_n_f32(bIn, o->step.f2sc)); + p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 3)); // http://stackoverflow.com/questions/11259596/arm-neon-intrinsics-rotation + p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 2)); + uint32x4_t pp = vaddq_u32(o->phase, vreinterpretq_u32_s32(p)); + *bOut = vsubq_f32(vreinterpretq_f32_u32(vorrq_u32(vshrq_n_u32(pp, 9), vdupq_n_u32(0x3F800000))), vdupq_n_f32(1.0f)); + o->phase = vdupq_n_u32(pp[3]); +#else // HV_SIMD_NONE + const hv_uint32_t p = (o->phase >> 9) | 0x3F800000; + *bOut = *((float *) (&p)) - 1.0f; + o->phase += ((int) (bIn * o->step.f2sc)); +#endif +} + +static inline void __hv_phasor_k_f(SignalPhasor *o, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + *bOut = _mm256_sub_ps(o->phase, _mm256_set1_ps(1.0f)); + o->phase = _mm256_or_ps(_mm256_andnot_ps( + _mm256_set1_ps(-INFINITY), + _mm256_add_ps(o->phase, o->inc)), + _mm256_set1_ps(1.0f)); +#elif HV_SIMD_SSE + *bOut = _mm_sub_ps(_mm_castsi128_ps( + _mm_or_si128(_mm_srli_epi32(o->phase, 9), + (__m128i) {0x3F8000003F800000L, 0x3F8000003F800000L})), + _mm_set1_ps(1.0f)); + o->phase = _mm_add_epi32(o->phase, o->inc); +#elif HV_SIMD_NEON + *bOut = vsubq_f32(vreinterpretq_f32_u32( + vorrq_u32(vshrq_n_u32(o->phase, 9), + vdupq_n_u32(0x3F800000))), + vdupq_n_f32(1.0f)); + o->phase = vaddq_u32(o->phase, vreinterpretq_u32_s32(o->inc)); +#else // HV_SIMD_NONE + const hv_uint32_t p = (o->phase >> 9) | 0x3F800000; + *bOut = *((float *) (&p)) - 1.0f; + o->phase += o->inc; +#endif +} + +#endif // _HEAVY_SIGNAL_PHASOR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalRPole.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalRPole.h" + +hv_size_t sRPole_init(SignalRPole *o) { +#if HV_SIMD_AVX + sDel1_init(&o->sDel1_fxiLN); + sDel1_init(&o->sDel1_kjkpV); + sDel1_init(&o->sDel1_dkIWc); + sDel1_init(&o->sDel1_bVeoW); + sDel1_init(&o->sDel1_PulZn); + sDel1_init(&o->sDel1_yTFig); + sDel1_init(&o->sDel1_Is9Qf); + sDel1_init(&o->sDel1_LIyNt); + sDel1_init(&o->sDel1_VqpU3); + sDel1_init(&o->sDel1_ZVYeg); + sDel1_init(&o->sDel1_IVAZh); + sDel1_init(&o->sDel1_F8WrY); + sDel1_init(&o->sDel1_rkFMy); + sDel1_init(&o->sDel1_BeqSK); + __hv_zero_f(&o->ym); +#elif HV_SIMD_SSE || HV_SIMD_NEON + sDel1_init(&o->sDel1_i8Twk); + sDel1_init(&o->sDel1_KYibU); + sDel1_init(&o->sDel1_spa5V); + sDel1_init(&o->sDel1_3HXdb); + sDel1_init(&o->sDel1_Aj1oK); + sDel1_init(&o->sDel1_jNX1g); + __hv_zero_f(&o->ym); +#else + o->ym = 0.0f; +#endif + return 0; +} + +void sRPole_onMessage(HvBase *_c, SignalRPole *o, int letIn, const HvMessage *m) { + // TODO +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalRPole.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SIGNAL_RPOLE_H_ +#define _SIGNAL_RPOLE_H_ + +#include "HvBase.h" +#include "SignalDel1.h" +#include "HeavyMath.h" + +// implements y[n] = x[n] - a*y[n-1] +// H(z) = 1/(1+a*z^-1) +typedef struct SignalRPole { +#if HV_SIMD_AVX + SignalDel1 sDel1_fxiLN; + SignalDel1 sDel1_kjkpV; + SignalDel1 sDel1_dkIWc; + SignalDel1 sDel1_bVeoW; + SignalDel1 sDel1_PulZn; + SignalDel1 sDel1_yTFig; + SignalDel1 sDel1_Is9Qf; + SignalDel1 sDel1_LIyNt; + SignalDel1 sDel1_VqpU3; + SignalDel1 sDel1_ZVYeg; + SignalDel1 sDel1_IVAZh; + SignalDel1 sDel1_F8WrY; + SignalDel1 sDel1_rkFMy; + SignalDel1 sDel1_BeqSK; + hv_bufferf_t ym; +#elif HV_SIMD_SSE || HV_SIMD_NEON + SignalDel1 sDel1_i8Twk; + SignalDel1 sDel1_KYibU; + SignalDel1 sDel1_spa5V; + SignalDel1 sDel1_3HXdb; + SignalDel1 sDel1_Aj1oK; + SignalDel1 sDel1_jNX1g; + hv_bufferf_t ym; +#else + hv_bufferf_t ym; +#endif +} SignalRPole; + +hv_size_t sRPole_init(SignalRPole *o); + +void sRPole_onMessage(HvBase *_c, SignalRPole *o, int letIn, const HvMessage *m); + +static inline void __hv_rpole_f(SignalRPole *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX + hv_bufferf_t a, b, c, d, e, f, g, i, j, k, l, m, n; + __hv_del1_f(&o->sDel1_fxiLN, bIn1, &a); + __hv_mul_f(bIn1, a, &b); + __hv_del1_f(&o->sDel1_kjkpV, a, &a); + __hv_mul_f(b, a, &c); + __hv_del1_f(&o->sDel1_dkIWc, a, &a); + __hv_mul_f(c, a, &d); + __hv_del1_f(&o->sDel1_bVeoW, a, &a); + __hv_mul_f(d, a, &e); + __hv_del1_f(&o->sDel1_PulZn, a, &a); + __hv_mul_f(e, a, &f); + __hv_del1_f(&o->sDel1_yTFig, a, &a); + __hv_mul_f(f, a, &g); + __hv_del1_f(&o->sDel1_Is9Qf, a, &a); + __hv_mul_f(g, a, &a); + __hv_del1_f(&o->sDel1_LIyNt, bIn0, &i); + __hv_del1_f(&o->sDel1_VqpU3, i, &j); + __hv_del1_f(&o->sDel1_ZVYeg, j, &k); + __hv_del1_f(&o->sDel1_IVAZh, k, &l); + __hv_del1_f(&o->sDel1_F8WrY, l, &m); + __hv_del1_f(&o->sDel1_rkFMy, m, &n); + __hv_mul_f(i, bIn1, &i); + __hv_sub_f(bIn0, i, &i); + __hv_fma_f(j, b, i, &i); + __hv_mul_f(k, c, &c); + __hv_sub_f(i, c, &c); + __hv_fma_f(l, d, c, &c); + __hv_mul_f(m, e, &e); + __hv_sub_f(c, e, &e); + __hv_fma_f(n, f, e, &e); + __hv_del1_f(&o->sDel1_BeqSK, n, &n); + __hv_mul_f(n, g, &g); + __hv_sub_f(e, g, &g); + __hv_fma_f(a, o->ym, g, &g); + o->ym = g; + *bOut = g; +#elif HV_SIMD_SSE || HV_SIMD_NEON + hv_bufferf_t a, b, c, e, f; + __hv_del1_f(&o->sDel1_i8Twk, bIn1, &a); + __hv_mul_f(bIn1, a, &b); + __hv_del1_f(&o->sDel1_KYibU, a, &a); + __hv_mul_f(b, a, &c); + __hv_del1_f(&o->sDel1_spa5V, a, &a); + __hv_mul_f(c, a, &a); + __hv_del1_f(&o->sDel1_3HXdb, bIn0, &e); + __hv_del1_f(&o->sDel1_Aj1oK, e, &f); + __hv_mul_f(e, bIn1, &e); + __hv_sub_f(bIn0, e, &e); + __hv_fma_f(f, b, e, &e); + __hv_del1_f(&o->sDel1_jNX1g, f, &f); + __hv_mul_f(f, c, &c); + __hv_sub_f(e, c, &c); + __hv_fma_f(a, o->ym, c, &c); + o->ym = c; + *bOut = c; +#else + *bOut = bIn0 - bIn1 * o->ym; + o->ym = *bOut; +#endif +} + +#endif // _SIGNAL_RPOLE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalSamphold.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalSamphold.h" + +hv_size_t sSamphold_init(SignalSamphold *o) { +#if HV_SIMD_AVX + o->s = _mm256_setzero_ps(); +#elif HV_SIMD_SSE + o->s = _mm_setzero_ps(); +#elif HV_SIMD_NEON + o->s = vdupq_n_f32(0.0f); +#else + o->s = 0.0f; +#endif + return 0; +} + +void sSamphold_onMessage(HvBase *_c, SignalSamphold *o, int letIndex, + const HvMessage *const m, void *sendMessage) { + switch (letIndex) { + case 2: { + if (msg_isFloat(m,0)) { +#if HV_SIMD_AVX + o->s = _mm256_set1_ps(msg_getFloat(m,0)); +#elif HV_SIMD_SSE + o->s = _mm_set1_ps(msg_getFloat(m,0)); +#elif HV_SIMD_NEON + o->s = vdupq_n_f32(msg_getFloat(m,0)); +#else + o->s = msg_getFloat(m,0); +#endif + } + break; + } + default: break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalSamphold.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,248 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SIGNAL_SAMPHOLD_H_ +#define _SIGNAL_SAMPHOLD_H_ + +#include "HvBase.h" + +typedef struct SignalSamphold { + hv_bufferf_t s; +} SignalSamphold; + +hv_size_t sSamphold_init(SignalSamphold *o); + +static inline void __hv_samphold_f(SignalSamphold *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { +#if HV_SIMD_AVX +#warning __hv_samphold_f() not implemented +#elif HV_SIMD_SSE + switch (_mm_movemask_ps(bIn1)) { + default: + case 0x0: *bOut = o->s; break; + case 0x1: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(0,0,0,0)); + o->s = *bOut; + break; + } + case 0x2: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(1,1,1,1)); + *bOut = _mm_blend_ps(o->s, x, 0xE); + o->s = x; + break; + } + case 0x3: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(1,1,1,1)); + *bOut = _mm_blend_ps(bIn0, x, 0xC); + o->s = x; + break; + } + case 0x4: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + *bOut = _mm_blend_ps(o->s, x, 0xC); + o->s = x; + break; + } + case 0x5: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,0,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + break; + } + case 0x6: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,1,0)); + *bOut = _mm_blend_ps(o->s, x, 0xE); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + break; + } + case 0x7: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); + *bOut = _mm_blend_ps(bIn0, x, 0x8); + o->s = x; + break; + } + case 0x8: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + *bOut = _mm_blend_ps(o->s, x, 0x8); + o->s = x; + break; + } + case 0x9: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,0,0,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xA: { + const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,1,1,0)); + *bOut = _mm_blend_ps(o->s, x, 0xE); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xB: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,1,1,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xC: { + *bOut = _mm_blend_ps(o->s, bIn0, 0xC); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xD: { + *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,2,0,0)); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xE: { + *bOut = _mm_blend_ps(o->s, bIn0, 0xE); + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + case 0xF: { + *bOut = bIn0; + o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); + break; + } + } +#elif HV_SIMD_NEON + uint32x4_t mmA = vandq_u32( + vreinterpretq_u32_f32(bIn1), (uint32x4_t) {0x1, 0x2, 0x4, 0x8}); // [0 1 2 3] + uint32x4_t mmB = vextq_u32(mmA, mmA, 2); // [2 3 0 1] + uint32x4_t mmC = vorrq_u32(mmA, mmB); // [0+2 1+3 0+2 1+3] + uint32x4_t mmD = vextq_u32(mmC, mmC, 3); // [1+3 0+2 1+3 0+2] + uint32x4_t mmE = vorrq_u32(mmC, mmD); // [0+1+2+3 ...] + uint32_t movemask = vgetq_lane_u32(mmE, 0); + switch (movemask) { + default: + case 0x0: *bOut = o->s; break; + case 0x1: { + *bOut = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + o->s = *bOut; + break; + } + case 0x2: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + *bOut = vextq_f32(o->s, x, 3); + o->s = x; + break; + } + case 0x3: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, ~0x0, ~0x0, ~0x0}))); + o->s = x; + break; + } + case 0x4: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); + *bOut = vextq_f32(o->s, x, 2); + o->s = x; + break; + } + case 0x5: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {~0x0, ~0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, ~0x0, ~0x0}))); + o->s = y; + } + case 0x6: { + const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + float32x4_t z = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, ~0x0, ~0x0, 0x0}))); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(z), (uint32x4_t) {~0x0, ~0x0, ~0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0x0, ~0x0}))); + o->s = y; + } + case 0x7: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, ~0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0x0, ~0x0, ~0x0}))); + o->s = x; + break; + } + case 0x8: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + *bOut = vextq_f32(o->s, x, 1); + o->s = x; + break; + } + case 0x9: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {~0x0, ~0x0, ~0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0x0, 0x0, ~0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + } + case 0xA: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + float32x4_t z = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, ~0x0, ~0x0, 0x0}))); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(z), (uint32x4_t) {~0x0, ~0x0, ~0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0x0, ~0x0}))); + o->s = y; + } + case 0xB: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, ~0x0, 0x0, ~0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0x0, ~0x0, 0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + case 0xC: { + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, ~0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0x0, ~0x0, ~0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + case 0xD: { + const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {~0x0, 0x0, ~0x0, ~0x0}), + vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, ~0x0, 0x0, 0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + } + case 0xE: { + *bOut = vreinterpretq_f32_u32(vorrq_u32( + vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {~0x0, 0x0, 0x0, 0x0}), + vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, ~0x0, ~0x0, ~0x0}))); + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + case 0xF: { + *bOut = bIn0; + o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); + break; + } + } +#else // HV_SIMD_NONE + if (bIn1 != 0.0f) o->s = bIn0; + *bOut = o->s; +#endif +} + +void sSamphold_onMessage(HvBase *_c, SignalSamphold *o, int letIndex, + const HvMessage *const m, void *sendMessage); + +#endif // _SIGNAL_SAMPHOLD_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalVar.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SignalVar.h" + +// __var~f + +static void sVarf_update(SignalVarf *o, float k, float step, bool reverse) { +#if HV_SIMD_AVX + if (reverse) o->v = _mm256_setr_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k); + else o->v = _mm256_set_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k); +#elif HV_SIMD_SSE + if (reverse) o->v = _mm_setr_ps(k+3.0f*step, k+2.0f*step, k+step, k); + else o->v = _mm_set_ps(k+3.0f*step, k+2.0f*step, k+step, k); +#elif HV_SIMD_NEON + if (reverse) o->v = (float32x4_t) {3.0f*step+k, 2.0f*step+k, step+k, k}; + else o->v = (float32x4_t) {k, step+k, 2.0f*step+k, 3.0f*step+k}; +#else // HV_SIMD_NONE + o->v = k; +#endif +} + +hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse) { + sVarf_update(o, k, step, reverse); + return 0; +} + +void sVarf_onMessage(HvBase *_c, SignalVarf *o, const HvMessage *m) { + if (msg_isFloat(m,0)) { + sVarf_update(o, msg_getFloat(m,0), msg_isFloat(m,1) ? msg_getFloat(m,1) : 0.0f, msg_getNumElements(m) == 3); + } +} + + + +// __var~i + +static void sVari_update(SignalVari *o, int k, int step, bool reverse) { +#if HV_SIMD_AVX + if (reverse) o->v = _mm256_setr_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k); + else o->v = _mm256_set_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k); +#elif HV_SIMD_SSE + if (reverse) o->v = _mm_setr_epi32(k+3*step, k+2*step, k+step, k); + else o->v = _mm_set_epi32(k+3*step, k+2*step, k+step, k); +#elif HV_SIMD_NEON + if (reverse) o->v = (int32x4_t) {3*step+k, 2*step+k, step+k, k}; + else o->v = (int32x4_t) {k, step+k, 2*step+k, 3*step+k}; +#else // HV_SIMD_NEON + o->v = k; +#endif +} + +hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse) { + sVari_update(o, k, step, reverse); + return 0; +} + +void sVari_onMessage(HvBase *_c, SignalVari *o, const HvMessage *m) { + if (msg_isFloat(m,0)) { + sVari_update(o, (int) msg_getFloat(m,0), msg_isFloat(m,1) ? (int) msg_getFloat(m,1) : 0, msg_getNumElements(m) == 3); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/SignalVar.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_SIGNAL_VAR_H_ +#define _HEAVY_SIGNAL_VAR_H_ + +#include "HvBase.h" + +// __var~f +// __varset~f + +typedef struct SignalVarf { + hv_bufferf_t v; +} SignalVarf; + +hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse); + +static inline void __hv_var_f(SignalVarf *o, hv_bOutf_t bOut) { + *bOut = o->v; +} + +static inline void sVarsetf_process(SignalVarf *o, hv_bInf_t bIn) { + o->v = bIn; +} + +void sVarf_onMessage(HvBase *_c, SignalVarf *o, const HvMessage *m); + + + +// __var~i +// __varset~i + +typedef struct SignalVari { + hv_bufferi_t v; +} SignalVari; + +hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse); + +static inline void __hv_var_i(SignalVari *o, hv_bOuti_t bOut) { + *bOut = o->v; +} + +#if HV_SIMD_AVX +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256i)(__v8si) {_a,_b,_c,_d,_e,_f,_g,_h}) +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256i)(__v8si) {_h,_g,_f,_e,_d,_c,_b,_a}) +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256) {_a,_b,_c,_d,_e,_f,_g,_h}) +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m256) {_h,_g,_f,_e,_d,_c,_b,_a}) +#elif HV_SIMD_SSE +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128i)(__v4si) {_a,_b,_c,_d}) +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128i)(__v4si) {_d,_c,_b,_a}) +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128) {_a,_b,_c,_d}) +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((__m128) {_d,_c,_b,_a}) +#elif HV_SIMD_NEON +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_a,_b,_c,_d}) +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_d,_c,_b,_a}) +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_a,_b,_c,_d}) +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_d,_c,_b,_a}) +#else // HV_SIMD_NONE +#define __hv_var_k_i_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#define __hv_var_k_i_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#define __hv_var_k_f_0(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#define __hv_var_k_f_1(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a +#endif +// r == 0: forwards, r == 1: backwards +#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h,_r) __hv_var_k_i_##_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) +#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h,_r) __hv_var_k_f_##_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) + +static inline void sVarseti_process(SignalVari *o, hv_bIni_t bIn) { + o->v = bIn; +} + +void sVari_onMessage(HvBase *_c, SignalVari *o, const HvMessage *m); + +#endif // _HEAVY_SIGNAL_VAR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_H_ +#define _HEAVY_UTILS_H_ + +// Type definitions +#if _WIN32 || _WIN64 || WINAPI_FAMILY +#define HV_WIN 1 +#include <stddef.h> +#if defined (_MSC_VER) +#define HV_MSVC 1 +#endif +#define hv_size_t unsigned long +#define hv_uint32_t unsigned int +#define hv_uint16_t unsigned short +#define hv_int32_t int +#elif __APPLE__ && __MACH__ +#define HV_APPLE 1 +#include <stddef.h> +#define hv_size_t size_t +#define hv_uint32_t unsigned int +#define hv_uint16_t unsigned short +#define hv_int32_t int +#elif __unix__ || __unix +#define HV_UNIX 1 +#include <stddef.h> +#include <stdint.h> +#define hv_size_t size_t +#define hv_uint32_t uint32_t +#define hv_uint16_t uint16_t +#define hv_int32_t int32_t +#else +#error Unsupported platform +#endif + +// Memory management +extern void *hv_alloca(hv_size_t numbytes); +extern void *hv_malloc(hv_size_t numbytes); // allocates memory on 16 byte boundaries and clears it to zero +extern void hv_free(void *ptr); // frees aligned memory +extern void *hv_realloc(void *ptr, hv_size_t numBytes); +extern void *hv_memcpy(void *dest, const void *src, hv_size_t numbytes); +extern void *hv_memset(void *ptr, hv_size_t numbytes); // sets everything to 0 + +// String handling +extern hv_size_t hv_strlen(const char *str); +extern char *hv_strncat(char *dest, const char *str, hv_size_t n); +extern char *hv_strncpy(char *dest, const char *str, hv_size_t n); +extern int hv_strcmp(const char *str1, const char *str2); +extern int hv_strncmp(const char *str1, const char *str2, hv_size_t n); +extern int hv_snprintf(char *dest, hv_size_t n, const char *format, ...); + +// Math +extern int hv_max_i(int x, int y); +extern hv_size_t hv_max_ui(hv_size_t x, hv_size_t y); +extern int hv_min_i(int x, int y); +extern hv_size_t hv_min_ui(hv_size_t x, hv_size_t y); +extern float hv_max_f(float x, float y); +extern float hv_min_f(float x, float y); +extern double hv_max_d(double x, double y); +extern double hv_min_d(double x, double y); +extern float hv_sin_f(float x); +extern float hv_sinh_f(float x); +extern float hv_cos_f(float x); +extern float hv_cosh_f(float x); +extern float hv_tan_f(float x); +extern float hv_tanh_f(float x); +extern float hv_asin_f(float x); +extern float hv_asinh_f(float x); +extern float hv_acos_f(float x); +extern float hv_acosh_f(float x); +extern float hv_atan_f(float x); +extern float hv_atanh_f(float x); +extern float hv_atan2_f(float x, float y); +extern float hv_exp_f(float x); +extern float hv_abs_f(float x); +extern float hv_sqrt_f(float x); +extern float hv_log_f(float x); +extern float hv_log2_f(float x); +extern float hv_log10_f(float x); +extern float hv_ceil_f(float x); +extern float hv_floor_f(float x); +extern float hv_round_f(float x); +extern float hv_pow_f(float x, float y); +extern float hv_fma_f(float x, float y, float z); + +// Utilities +extern void hv_assert(int e); +extern void hv_clear_buffer(float *b, int n); +extern hv_uint32_t hv_min_max_log2(hv_uint32_t x); + +// SIMD +#ifndef HV_SIMD_NONE + #define HV_SIMD_NEON __ARM_NEON__ + #define HV_SIMD_SSE (__SSE__ && __SSE2__ && __SSE3__ && __SSSE3__ && __SSE4_1__) + #define HV_SIMD_AVX (__AVX__ && HV_SIMD_SSE) // it is required that if AVX exists then SSE will also be available + #define HV_SIMD_FMA __FMA__ +#endif + +#ifdef HV_WIN +#include "Utils_windows.h" +#elif HV_APPLE +#include "Utils_mac.h" +#elif HV_UNIX +#include "Utils_unix.h" +#else +#error Unsupported platform +#endif + +#if HV_SIMD_NEON // NEON + #define HV_N_SIMD 4 + #define hv_bufferf_t float32x4_t + #define hv_bufferi_t int32x4_t + #define hv_bInf_t float32x4_t + #define hv_bOutf_t float32x4_t* + #define hv_bIni_t int32x4_t + #define hv_bOuti_t int32x4_t* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#elif HV_SIMD_AVX // AVX + #define HV_N_SIMD 8 + #define hv_bufferf_t __m256 + #define hv_bufferi_t __m256i + #define hv_bInf_t __m256 + #define hv_bOutf_t __m256* + #define hv_bIni_t __m256i + #define hv_bOuti_t __m256i* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#elif HV_SIMD_SSE // SSE + #define HV_N_SIMD 4 + #define hv_bufferf_t __m128 + #define hv_bufferi_t __m128i + #define hv_bInf_t __m128 + #define hv_bOutf_t __m128* + #define hv_bIni_t __m128i + #define hv_bOuti_t __m128i* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#else // DEFAULT + #define HV_N_SIMD 1 + #undef HV_SIMD_NONE + #define HV_SIMD_NONE 1 + #define hv_bufferf_t float + #define hv_bufferi_t int + #define hv_bInf_t float + #define hv_bOutf_t float* + #define hv_bIni_t int + #define hv_bOuti_t int* + #define VIf(_x) (_x) + #define VOf(_x) (&_x) + #define VIi(_x) (_x) + #define VOi(_x) (&_x) +#endif + +#define HV_N_SIMD_MASK (HV_N_SIMD-1) + +#endif // _HEAVY_UTILS_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils_mac.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Utils_mac.h" + +#if HV_APPLE + +hv_size_t hv_max_ui(hv_size_t x, hv_size_t y) { + return (x >= y) ? x : y; +} + +hv_size_t hv_min_ui(hv_size_t x, hv_size_t y) { + return (x <= y) ? x : y; +} + +int hv_max_i(int x, int y) { + return (x >= y) ? x : y; +} + +int hv_min_i(int x, int y) { + return (x <= y) ? x : y; +} + +hv_uint32_t hv_min_max_log2(hv_uint32_t x) { + // finds ceil(log2(x)) + // http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + return (hv_uint32_t) ((8 * sizeof(unsigned int)) - __builtin_clz(x - 1)); +} + +#endif // HV_APPLE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils_mac.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_MAC_H_ +#define _HEAVY_UTILS_MAC_H_ + +#include "Utils.h" + +#if HV_APPLE +#include <alloca.h> +#if HV_SIMD_AVX || HV_SIMD_SSE +#include <immintrin.h> +#include <mm_malloc.h> +#elif HV_SIMD_NEON +#include <arm_neon.h> +#endif +#include <assert.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HV_EXPORT +#define HV_FORCE_INLINE inline __attribute__((always_inline)) + +// Memory management +#define hv_alloca(_n) alloca(_n) +#if HV_SIMD_AVX || HV_SIMD_SSE + #define hv_malloc(_n) _mm_malloc(_n, 32) // 32 to ensure AVX compatability (16 otherwise) + #define hv_free(x) _mm_free(x) +#else + #define hv_malloc(_n) malloc(_n) + #define hv_free(x) free(x) +#endif +#define hv_realloc(a, b) realloc(a, b) +#define hv_memcpy(a, b, c) memcpy(a, b, c) +#define hv_memset(a, b) memset(a, 0, b) + +// Strings +#define hv_strlen(a) strlen(a) +#define hv_strncat(a, b, c) strncat(a, b, c) +#define hv_strncpy(a, b, c) strncpy(a, b, c) +#define hv_strcmp(a, b) strcmp(a, b) +#define hv_strncmp(a, b, c) strncmp(a, b, c) +#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) + +// Math +#define hv_max_f(a, b) fmaxf(a, b) +#define hv_min_f(a, b) fminf(a, b) +#define hv_max_d(a, b) fmax(a, b) +#define hv_min_d(a, b) fmin(a, b) +#define hv_sin_f(a) sinf(a) +#define hv_sinh_f(a) sinhf(a) +#define hv_cos_f(a) cosf(a) +#define hv_cosh_f(a) coshf(a) +#define hv_tan_f(a) tanf(a) +#define hv_tanh_f(a) tanhf(a) +#define hv_asin_f(a) asinf(a) +#define hv_asinh_f(a) asinhf(a) +#define hv_acos_f(a) acosf(a) +#define hv_acosh_f(a) acoshf(a) +#define hv_atan_f(a) atanf(a) +#define hv_atanh_f(a) atanhf(a) +#define hv_atan2_f(a, b) atan2f(a, b) +#define hv_exp_f(a) expf(a) +#define hv_abs_f(a) fabsf(a) +#define hv_sqrt_f(a) sqrtf(a) +#define hv_log_f(a) logf(a) +#define hv_log2_f(a) log2f(a) +#define hv_log10_f(a) log10f(a) +#define hv_ceil_f(a) ceilf(a) +#define hv_floor_f(a) floorf(a) +#define hv_round_f(a) roundf(a) +#define hv_pow_f(a, b) powf(a, b) +#define hv_fma_f(a, b, c) ((a*b)+c) // TODO(joe): use 'fmaf(a, b, c)' once emscripten supports it + +// Utilities +#define hv_assert(e) assert(e) +#define hv_clear_buffer(b, n) memset(b, 0, (n)*sizeof(float)) + +#endif // HV_APPLE +#endif // _HEAVY_UTILS_MAC_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils_unix.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Utils_unix.h" + +#if HV_UNIX + +hv_size_t hv_max_ui(hv_size_t x, hv_size_t y) { + return (x >= y) ? x : y; +} + +hv_size_t hv_min_ui(hv_size_t x, hv_size_t y) { + return (x <= y) ? x : y; +} + +int hv_max_i(int x, int y) { + return (x >= y) ? x : y; +} + +int hv_min_i(int x, int y) { + return (x <= y) ? x : y; +} + +hv_uint32_t hv_min_max_log2(hv_uint32_t x) { + // finds ceil(log2(x)) + // http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + return (hv_uint32_t) ((8 * sizeof(unsigned int)) - __builtin_clz(x - 1)); +} + +#endif // HV_UNIX
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils_unix.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_UNIX_H_ +#define _HEAVY_UTILS_UNIX_H_ + +#include "Utils.h" + +#if HV_UNIX +#if HV_SIMD_AVX || HV_SIMD_SSE +#include <immintrin.h> +#include <mm_malloc.h> +#elif HV_SIMD_NEON +#include <arm_neon.h> +#endif +#include <alloca.h> +#include <assert.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HV_EXPORT +#define HV_FORCE_INLINE inline __attribute__((always_inline)) + +// Memory management +#define hv_alloca(_n) alloca(_n) +#if HV_SIMD_AVX || HV_SIMD_SSE + #define hv_malloc(_n) _mm_malloc(_n, 32) // 32 to ensure AVX compatability (16 otherwise) + #define hv_free(x) _mm_free(x) +#else + #define hv_malloc(_n) malloc(_n) + #define hv_free(_n) free(_n) +#endif +#define hv_realloc(a, b) realloc(a, b) +#define hv_memcpy(a, b, c) memcpy(a, b, c) +#define hv_memset(a, b) memset(a, 0, b) + +// Strings +#define hv_strlen(a) strlen(a) +#define hv_strncat(a, b, c) strncat(a, b, c) +#define hv_strncpy(a, b, c) strncpy(a, b, c) +#define hv_strcmp(a, b) strcmp(a, b) +#define hv_strncmp(a, b, c) strncmp(a, b, c) +#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) + +// Math +#define hv_max_f(a, b) fmaxf(a, b) +#define hv_min_f(a, b) fminf(a, b) +#define hv_max_d(a, b) fmax(a, b) +#define hv_min_d(a, b) fmin(a, b) +#define hv_sin_f(a) sinf(a) +#define hv_sinh_f(a) sinhf(a) +#define hv_cos_f(a) cosf(a) +#define hv_cosh_f(a) coshf(a) +#define hv_tan_f(a) tanf(a) +#define hv_tanh_f(a) tanhf(a) +#define hv_asin_f(a) asinf(a) +#define hv_asinh_f(a) asinhf(a) +#define hv_acos_f(a) acosf(a) +#define hv_acosh_f(a) acoshf(a) +#define hv_atan_f(a) atanf(a) +#define hv_atanh_f(a) atanhf(a) +#define hv_atan2_f(a, b) atan2f(a, b) +#define hv_exp_f(a) expf(a) +#define hv_abs_f(a) fabsf(a) +#define hv_sqrt_f(a) sqrtf(a) +#define hv_log_f(a) logf(a) +#define hv_log2_f(a) log2f(a) +#define hv_log10_f(a) log10f(a) +#define hv_ceil_f(a) ceilf(a) +#define hv_floor_f(a) floorf(a) +#define hv_round_f(a) roundf(a) +#define hv_pow_f(a, b) powf(a, b) +#define hv_fma_f(a, b, c) ((a*b)+c) // TODO(joe): use 'fmaf(a, b, c)' once emscripten supports it + +// Utilities +#define hv_assert(e) assert(e) +#define hv_clear_buffer(b, n) memset(b, 0, n*sizeof(float)) + +#endif // HV_UNIX +#endif // _HEAVY_UTILS_UNIX_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils_windows.c Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Utils_windows.h" + +#if HV_WIN + +hv_size_t hv_max_ui(hv_size_t x, hv_size_t y) { + return (x >= y) ? x : y; +} + +hv_size_t hv_min_ui(hv_size_t x, hv_size_t y) { + return (x <= y) ? x : y; +} + +int hv_max_i(int x, int y) { + return (x >= y) ? x : y; +} + +int hv_min_i(int x, int y) { + return (x <= y) ? x : y; +} + +hv_uint32_t hv_min_max_log2(hv_uint32_t x) { +#if HV_MSVC + // finds ceil(log2(x)) + // http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + // http://msdn.microsoft.com/en-us/library/fbxyd7zd%28v=VS.80%29.aspx + unsigned long z = 0; + _BitScanReverse(&z, x); + return (hv_uint32_t) (z+1); +#else + return (hv_uint32_t) ((8 * sizeof(unsigned int)) - __builtin_clz(x-1)); +#endif // HV_MSVC +} + +#if HV_MSVC +int hv_snprintf(char* str, hv_size_t size, const char* format, ...) { + // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + int count = -1; + va_list ap; + va_start(ap, format); + + if (size != 0) { + count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + } + if (count == -1) { + count = _vscprintf(format, ap); + } + va_end(ap); + return count; +} +#endif // HV_MSVC +#endif // HV_WIN +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/Utils_windows.h Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HEAVY_UTILS_WINDOWS_H_ +#define _HEAVY_UTILS_WINDOWS_H_ + +#include "Utils.h" + +#if HV_WIN +#define _USE_MATH_DEFINES +#if HV_SIMD_AVX || HV_SIMD_SSE +#if HV_MSVC +#include <intrin.h> +#else +#include <immintrin.h> +#endif +#elif HV_SIMD_NEON +#include <arm_neon.h> +#endif +#include <malloc.h> +#include <assert.h> +#include <math.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +#define HV_EXPORT __declspec(dllexport) + +// MSVC Specific +#if HV_MSVC +#define inline __inline +#define HV_FORCE_INLINE __forceinline +#else +#define HV_FORCE_INLINE inline __attribute__((always_inline)) +#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) +#endif // HV_MSVC + +// Memory management +#define hv_alloca(_n) _alloca(_n) +#if !defined(HV_SIMD_AVX) || !defined(HV_SIMD_SSE) +#define hv_malloc(_n) _aligned_malloc(_n, 32) +#define hv_free(x) _aligned_free(x) +#else +#define hv_malloc(_n) malloc(_n) +#define hv_free(_n) free(_n) +#endif +#define hv_realloc(a, b) realloc(a, b) +#define hv_memcpy(a, b, c) memcpy(a, b, c) +#define hv_memset(a, b) memset(a, 0, b) + +// Strings +#define hv_strncat(a, b, c) strncat(a, b, c) +#define hv_strcmp(a, b) strcmp(a, b) +#define hv_strncmp(a, b, c) strncmp(a, b, c) +#define hv_strncpy(a, b, c) strncpy(a, b, c) +#define hv_strlen(a) strlen(a) + +// Math +#define hv_max_f(a, b) fmaxf(a, b) +#define hv_min_f(a, b) fminf(a, b) +#define hv_max_d(a, b) fmax(a, b) +#define hv_min_d(a, b) fmin(a, b) +#define hv_sin_f(a) sinf(a) +#define hv_sinh_f(a) sinhf(a) +#define hv_cos_f(a) cosf(a) +#define hv_cosh_f(a) coshf(a) +#define hv_tan_f(a) tanf(a) +#define hv_tanh_f(a) tanhf(a) +#define hv_asin_f(a) asinf(a) +#define hv_asinh_f(a) asinhf(a) +#define hv_acos_f(a) acosf(a) +#define hv_acosh_f(a) acoshf(a) +#define hv_atan_f(a) atanf(a) +#define hv_atanh_f(a) atanhf(a) +#define hv_atan2_f(a, b) atan2f(a, b) +#define hv_exp_f(a) expf(a) +#define hv_abs_f(a) fabsf(a) +#define hv_sqrt_f(a) sqrtf(a) +#define hv_log_f(a) logf(a) +#define hv_log2_f(a) log2f(a) +#define hv_log10_f(a) log10f(a) +#define hv_ceil_f(a) ceilf(a) +#define hv_floor_f(a) floorf(a) +#define hv_round_f(a) roundf(a) +#define hv_pow_f(a, b) powf(a, b) +#define hv_fma_f(a, b, c) ((a*b)+c) // TODO(joe): use 'fmaf(a, b, c)' once emscripten supports it + +// Utilities +#define hv_assert(e) assert(e) +#define hv_clear_buffer(b, n) memset(b, 0, n*sizeof(float)) + +#endif // HV_WIN +#endif // _HEAVY_UTILS_WINDOWS_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/samphold/render.cpp Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,183 @@ +/* + * render.cpp + * + * Template render.cpp file for on-board heavy compiling + * + * N.B. this is currently *not* compatible with foleyDesigner source files! + * + * Created on: November 5, 2015 + * + * Christian Heinrichs + * + */ + +#include <BeagleRT.h> +#include <cmath> +#include "../include/Utilities.h" +#include "Heavy_bbb.h" + +// #include "I2c_TouchKey.h" + +// #include "../include/UdpServer.h" +// #include "../include/UdpClient.h" +// #include <iostream> +// #include <fstream> +// #include "../include/ReceiveAudioThread.h" + +// #include "../include/render.h" +// #include <arm_neon.h> +// #include <time.h> +// #include <sndfile.h> + +// #include "../include/RTAudio.h" +// #include <rtdk.h> + + +/* + * HEAVY CONTEXT & BUFFERS + */ + +Hv_bbb *gHeavyContext; +float *gHvInputBuffers = NULL, *gHvOutputBuffers = NULL; +int gHvInputChannels = 0, gHvOutputChannels = 0; + +float gInverseSampleRate; + +/* + * HEAVY FUNCTIONS + */ + +void printHook(double timestampSecs, const char *printLabel, const char *msgString, void *userData) { + printf("Message from Heavy patch: [@ %.3f] %s: %s\n", timestampSecs, printLabel, msgString); +} + +static void sendHook( + double timestamp, // in milliseconds + const char *receiverName, + const HvMessage *const m, + void *userData) { + + // only react to messages sent to receivers named "hello" + if (!strncmp(receiverName, "hello", 5)) { + } + +} + +/* + * RENDER INITIALISATION, LOOP & CLEANUP + */ + + +// bool initialise_render(int numMatrixChannels, int numAudioChannels, +// int numMatrixFramesPerPeriod, +// int numAudioFramesPerPeriod, +// float matrixSampleRate, float audioSampleRate, +// void *userData) +// { +bool setup(BeagleRTContext *context, void *userData) { + + /* HEAVY */ + + gHeavyContext = hv_bbb_new(context->audioSampleRate); + + gHvInputChannels = hv_getNumInputChannels(gHeavyContext); + gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext); + + // srand ( time(NULL) ); + + rt_printf("Starting Heavy context with %d input channels and %d output channels\n", + gHvInputChannels, gHvOutputChannels); + + if(gHvInputChannels != 0) { + gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float)); + //memset(gHvInputBuffers,0,gHvInputChannels * numAudioFramesPerPeriod * sizeof(float)); + } + if(gHvOutputChannels != 0) { + gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float)); + } + + gInverseSampleRate = 1.0 / context->audioSampleRate; + + // Set heavy print hook + hv_setPrintHook(gHeavyContext, &printHook); + // Set heavy send hook + hv_setSendHook(gHeavyContext, sendHook); + + return true; +} + + +// void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, +// uint16_t *matrixIn, uint16_t *matrixOut) +// { +void render(BeagleRTContext *context, void *userData) +{ + // use this for thread management + // if(gCount == 0) { + // } else { + // } + // gCount++; + + // De-interleave the data + if(gHvInputBuffers != NULL) { + for(int n = 0; n < context->audioFrames; n++) { + for(int ch = 0; ch < gHvInputChannels; ch++) { + if(ch >= context->audioChannels+context->analogChannels) { + // THESE ARE PARAMETER INPUT 'CHANNELS' USED FOR ROUTING + // 'sensor' outputs from routing channels of dac~ are passed through here + break; + } else { + // If more than 2 ADC inputs are used in the pd patch, route the analog inputs + // i.e. ADC3->analogIn0 etc. (first two are always audio inputs) + if(ch >= context->audioChannels) { + int m = n/2; + float mIn = context->analogIn[m*context->analogChannels + (ch-context->audioChannels)]; + gHvInputBuffers[ch * context->audioFrames + n] = mIn; + } else { + gHvInputBuffers[ch * context->audioFrames + n] = context->audioIn[n * context->audioChannels + ch]; + } + } + } + } + } + + // replacement for bang~ object + //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b"); + + hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames); + + // Interleave the output data + if(gHvOutputBuffers != NULL) { + for(int n = 0; n < context->audioFrames; n++) { + + for(int ch = 0; ch < gHvOutputChannels; ch++) { + if(ch >= context->audioChannels+context->analogChannels) { + // THESE ARE SENSOR OUTPUT 'CHANNELS' USED FOR ROUTING + // they are the content of the 'sensor output' dac~ channels + } else { + if(ch >= context->audioChannels) { + int m = n/2; + // float mOut = (float)gHvOutputBuffers[ch*numAudioFrames + n]; + // mOut = constrain(mOut,0.0,1.0); + context->analogOut[m * context->analogFrames + (ch-context->audioChannels)] = constrain(gHvOutputBuffers[ch*context->audioFrames + n],0.0,1.0); + } else { + context->audioOut[n * context->audioChannels + ch] = gHvOutputBuffers[ch * context->audioFrames + n]; + } + } + } + } + } + +} + + +void cleanup(BeagleRTContext *context, void *userData) +{ + + hv_bbb_free(gHeavyContext); + if(gHvInputBuffers != NULL) + free(gHvInputBuffers); + if(gHvOutputBuffers != NULL) + free(gHvOutputBuffers); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/build_pd.sh Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,107 @@ +#!/bin/bash + +# shell script for automatic uploading/compiling of pd patch onto bbb +# Christian Heinrichs 2015 +# +# example usage: sh upload-and-compile.sh -f bwg-tests -q -e + +workingdir=".." +verbose="0" +render="0" +pdpath="" +projectpath="../projects/heavy/hvtemp" +BBB_PATH="~/BeagleRT" +BBB_ADDRESS="root@192.168.7.2" +COMMAND_ARGS= +RUN_PROJECT=1 +RUN_IN_FOREGROUND=0 +RUN_WITHOUT_SCREEN=1 + +function usage +{ + echo " + USAGE: build_pd.sh [[-i input folder containing _main.pd file ] [-o output folder for new heavy project .c files (default ../projects/heavy/hvtemp)] [-b bbb path to copy to (default ~/BeagleRT)] | [-h]] + " + echo "example: build_pd.sh -i ../projects/heavy/pd/hello-world -o ../projects/heavy/hello-world" +} + +while [ "$1" != "" ]; do + case $1 in + -b | --bbb ) shift + BBB_PATH=$1 + ;; + -i | --input ) shift + pdpath=$1 + ;; + -o | --output ) shift + projectpath=$1 + ;; + -v | --verbose ) shift + verbose=1 + ;; + -r | --render ) shift + render=1 + ;; + -h | --help ) usage + exit + ;; + * ) usage + exit 1 + esac + shift +done + +/usr/bin/python hvresources/uploader.py "$pdpath"/ -n bbb -g c -o "$projectpath"/; +if [ $? -ne 0 ]; then + /usr/local/bin/python hvresources/uploader.py "$pdpath"/ -n bbb -g c -o "$projectpath"/; + if [ $? -ne 0 ]; then + #echo "ERROR: an error occurred while executing the uploader.py script" + echo "error" + exit 1 + fi; +fi; +echo ""; +#echo "*|*|* Successfully uploaded and converted pd patch into super-fast optimized C code. Brought to you by Heavy! *|*|*"; +echo ""; + +# check how to copy/sync render.cpp file... +if [ $render -eq 0 ]; then + cp "hvresources/render.cpp" $projectpath/; +fi; + +rsync -c -r "$projectpath"/ "$BBB_ADDRESS":"$BBB_PATH"/source; + +if [ $? -ne 0 ]; then + echo ""; + echo ":( :( :( ERROR: while synchronizing files with the BBB. Is the board connected and the correct SD card inserted? :( :( :("; + echo ""; + exit 1; +fi; + +# Make new BeagleRT executable and run +if [ $RUN_PROJECT -eq 0 ] +then + echo "Building project..." + ssh $BBB_ADDRESS "make all -C $BBB_PATH" +else + echo "Building and running project..." + + if [ $RUN_WITHOUT_SCREEN -ne 0 ] + then + ssh -t $BBB_ADDRESS "make all -C $BBB_PATH && $BBB_PATH/BeagleRT $COMMAND_ARGS" + elif [ $RUN_IN_FOREGROUND -eq 0 ] + then + ssh $BBB_ADDRESS "make all -C $BBB_PATH && screen -S BeagleRT -d -m $BBB_PATH/BeagleRT $COMMAND_ARGS" + else + ssh -t $BBB_ADDRESS "make all -C $BBB_PATH && screen -S BeagleRT $BBB_PATH/BeagleRT $COMMAND_ARGS" + fi +fi + + + + + + + + +#ssh -t root@192.168.7.2 "kill -s 2 \`pidof heavy_template\` 2>/dev/null; sleep 0.5; rm -f ~/$filename_bbb/Release/source/heavy/HvContext_bbb.? ~/$filename_bbb/Release/heavy_template && make all -C ~/$filename_bbb/Release" &>/dev/null
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/hvresources/render.cpp Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,183 @@ +/* + * render.cpp + * + * Template render.cpp file for on-board heavy compiling + * + * N.B. this is currently *not* compatible with foleyDesigner source files! + * + * Created on: November 5, 2015 + * + * Christian Heinrichs + * + */ + +#include <BeagleRT.h> +#include <cmath> +#include "../include/Utilities.h" +#include "Heavy_bbb.h" + +// #include "I2c_TouchKey.h" + +// #include "../include/UdpServer.h" +// #include "../include/UdpClient.h" +// #include <iostream> +// #include <fstream> +// #include "../include/ReceiveAudioThread.h" + +// #include "../include/render.h" +// #include <arm_neon.h> +// #include <time.h> +// #include <sndfile.h> + +// #include "../include/RTAudio.h" +// #include <rtdk.h> + + +/* + * HEAVY CONTEXT & BUFFERS + */ + +Hv_bbb *gHeavyContext; +float *gHvInputBuffers = NULL, *gHvOutputBuffers = NULL; +int gHvInputChannels = 0, gHvOutputChannels = 0; + +float gInverseSampleRate; + +/* + * HEAVY FUNCTIONS + */ + +void printHook(double timestampSecs, const char *printLabel, const char *msgString, void *userData) { + printf("Message from Heavy patch: [@ %.3f] %s: %s\n", timestampSecs, printLabel, msgString); +} + +static void sendHook( + double timestamp, // in milliseconds + const char *receiverName, + const HvMessage *const m, + void *userData) { + + // only react to messages sent to receivers named "hello" + if (!strncmp(receiverName, "hello", 5)) { + } + +} + +/* + * RENDER INITIALISATION, LOOP & CLEANUP + */ + + +// bool initialise_render(int numMatrixChannels, int numAudioChannels, +// int numMatrixFramesPerPeriod, +// int numAudioFramesPerPeriod, +// float matrixSampleRate, float audioSampleRate, +// void *userData) +// { +bool setup(BeagleRTContext *context, void *userData) { + + /* HEAVY */ + + gHeavyContext = hv_bbb_new(context->audioSampleRate); + + gHvInputChannels = hv_getNumInputChannels(gHeavyContext); + gHvOutputChannels = hv_getNumOutputChannels(gHeavyContext); + + // srand ( time(NULL) ); + + rt_printf("Starting Heavy context with %d input channels and %d output channels\n", + gHvInputChannels, gHvOutputChannels); + + if(gHvInputChannels != 0) { + gHvInputBuffers = (float *)calloc(gHvInputChannels * context->audioFrames,sizeof(float)); + //memset(gHvInputBuffers,0,gHvInputChannels * numAudioFramesPerPeriod * sizeof(float)); + } + if(gHvOutputChannels != 0) { + gHvOutputBuffers = (float *)calloc(gHvOutputChannels * context->audioFrames,sizeof(float)); + } + + gInverseSampleRate = 1.0 / context->audioSampleRate; + + // Set heavy print hook + hv_setPrintHook(gHeavyContext, &printHook); + // Set heavy send hook + hv_setSendHook(gHeavyContext, sendHook); + + return true; +} + + +// void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, +// uint16_t *matrixIn, uint16_t *matrixOut) +// { +void render(BeagleRTContext *context, void *userData) +{ + // use this for thread management + // if(gCount == 0) { + // } else { + // } + // gCount++; + + // De-interleave the data + if(gHvInputBuffers != NULL) { + for(int n = 0; n < context->audioFrames; n++) { + for(int ch = 0; ch < gHvInputChannels; ch++) { + if(ch >= context->audioChannels+context->analogChannels) { + // THESE ARE PARAMETER INPUT 'CHANNELS' USED FOR ROUTING + // 'sensor' outputs from routing channels of dac~ are passed through here + break; + } else { + // If more than 2 ADC inputs are used in the pd patch, route the analog inputs + // i.e. ADC3->analogIn0 etc. (first two are always audio inputs) + if(ch >= context->audioChannels) { + int m = n/2; + float mIn = context->analogIn[m*context->analogChannels + (ch-context->audioChannels)]; + gHvInputBuffers[ch * context->audioFrames + n] = mIn; + } else { + gHvInputBuffers[ch * context->audioFrames + n] = context->audioIn[n * context->audioChannels + ch]; + } + } + } + } + } + + // replacement for bang~ object + //hv_vscheduleMessageForReceiver(gHeavyContext, "bbb_bang", 0.0f, "b"); + + hv_bbb_process_inline(gHeavyContext, gHvInputBuffers, gHvOutputBuffers, context->audioFrames); + + // Interleave the output data + if(gHvOutputBuffers != NULL) { + for(int n = 0; n < context->audioFrames; n++) { + + for(int ch = 0; ch < gHvOutputChannels; ch++) { + if(ch >= context->audioChannels+context->analogChannels) { + // THESE ARE SENSOR OUTPUT 'CHANNELS' USED FOR ROUTING + // they are the content of the 'sensor output' dac~ channels + } else { + if(ch >= context->audioChannels) { + int m = n/2; + // float mOut = (float)gHvOutputBuffers[ch*numAudioFrames + n]; + // mOut = constrain(mOut,0.0,1.0); + context->analogOut[m * context->analogFrames + (ch-context->audioChannels)] = constrain(gHvOutputBuffers[ch*context->audioFrames + n],0.0,1.0); + } else { + context->audioOut[n * context->audioChannels + ch] = gHvOutputBuffers[ch * context->audioFrames + n]; + } + } + } + } + } + +} + + +void cleanup(BeagleRTContext *context, void *userData) +{ + + hv_bbb_free(gHeavyContext); + if(gHvInputBuffers != NULL) + free(gHvInputBuffers); + if(gHvOutputBuffers != NULL) + free(gHvOutputBuffers); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/hvresources/uploader.py Thu Nov 05 18:58:26 2015 +0000 @@ -0,0 +1,280 @@ +#!/usr/bin/python + +# Copyright 2015 Section6. All Rights Reserved. + +import argparse +import getpass +import json +import os +import requests +import shutil +import stat +import tempfile +import time +import urlparse +import zipfile +import sys + +class Colours: + purple = "\033[95m" + cyan = "\033[96m" + dark_cyan = "\033[36m" + blue = "\033[94m" + green = "\033[92m" + yellow = "\033[93m" + red = "\033[91m" + bold = "\033[1m" + underline = "\033[4m" + end = "\033[0m" + +def __zip_dir(in_dir, zip_path, file_filter=None): + zf = zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) + for subdir, dirs, files in os.walk(in_dir): + for file in files: + if (file_filter is None) or (len(file_filter) > 0 and file.lower().split(".")[-1] in file_filter): + zf.write( + filename=os.path.join(subdir,file), + arcname=os.path.relpath(os.path.join(subdir,file), start=in_dir)) + return zip_path + +def __unzip(zip_path, target_dir): + """Unzip a file to a given directory. All destination files are overwritten. + """ + zipfile.ZipFile(zip_path).extractall(target_dir) + +def main(): + parser = argparse.ArgumentParser( + description="Compiles a Pure Data file.") + parser.add_argument( + "input_dir", + help="A directory containing _main.pd. The entire directory will be uploaded.") + parser.add_argument( + "-n", "--name", + default="heavy", + help="Patch name. If it doesn't exist, the uploader will fail. Make sure that it exists on the Heavy website.") + parser.add_argument( + "-g", "--gen", + nargs="+", + default=["c"], + help="List of generator outputs. Currently supported generators are 'c' and 'js'.") + parser.add_argument( + "-b", + help="All files will be placed in the output directory, placed in their own subdirectory corresonding to the generator name.", + action="count") + parser.add_argument( + "-o", "--out", + nargs="+", + default=["./"], # by default + help="List of destination directories for retrieved files. Order should be the same as for --gen.") + parser.add_argument( + "-d", "--domain", + default="https://enzienaudio.com", + help="Domain. Default is https://enzienaudio.com.") + parser.add_argument( + "-x", + help="Don't save the returned token.", + action="count") + parser.add_argument( + "-z", + help="Force the use of a password, regardless of saved token.", + action="count") + parser.add_argument( + "--noverify", + help="Don't verify the SSL connection. Generally a bad idea.", + action="count") + parser.add_argument( + "-v", "--verbose", + help="Show debugging information.", + action="count") + args = parser.parse_args() + + domain = args.domain or "https://enzienaudio.com" + + post_data = {} + + # token should be stored in ~/.heavy/token + token_path = os.path.expanduser(os.path.join("~/", ".heavy", "token")) + if os.path.exists(token_path) and not args.z: + with open(token_path, "r") as f: + post_data["credentials"] = { + "token": f.read() + } + else: + # otherwise, get the username and password + post_data["credentials"] = { + "username": raw_input("Enter username: "), + "password": getpass.getpass("Enter password: ") + } + + tick = time.time() + + # make a temporary directory + temp_dir = tempfile.mkdtemp(prefix="lroyal-") + + # zip up the pd directory into the temporary directory + try: + if not os.path.exists(os.path.join(args.input_dir, "_main.pd")): + raise Exception("Root Pd directory does not contain a file named _main.pd.") + zip_path = __zip_dir( + args.input_dir, + os.path.join(temp_dir, "archive.zip"), + file_filter={"pd"}) + except Exception as e: + print e + shutil.rmtree(temp_dir) # clean up the temporary directory + return + + post_data["name"] = args.name + + # the outputs to generate (always include c) + __SUPPORTED_GENERATOR_SET = {"c", "js"} + post_data["gen"] = list(({"c"} | set(args.gen)) & __SUPPORTED_GENERATOR_SET) + + # upload the job, get the response back + # NOTE(mhroth): multipart-encoded file can only be sent as a flat dictionary, + # but we want to send a json encoded deep dictionary. So we do a bit of a hack. + r = requests.post( + urlparse.urljoin(domain, "/a/heavy"), + data={"json":json.dumps(post_data)}, + files={"file": (os.path.basename(zip_path), open(zip_path, "rb"), "application/zip")}, + verify=False if args.noverify else True) + + if r.status_code != requests.codes.ok: + shutil.rmtree(temp_dir) # clean up the temporary directory + r.raise_for_status() # raise an exception + + # decode the JSON API response + r_json = r.json() + + """ + { + "data": { + "compileTime": 0.05078411102294922, + "id": "mhroth/asdf/Edp2G", + "slug": "Edp2G", + "index": 3, + "links": { + "files": { + "linkage": [ + { + "id": "mhroth/asdf/Edp2G/c", + "type": "file" + } + ], + "self": "https://enzienaudio.com/h/mhroth/asdf/Edp2G/files" + }, + "project": { + "linkage": { + "id": "mhroth/asdf", + "type": "project" + }, + "self": "https://enzienaudio.com/h/mhroth/asdf" + }, + "self": "https://enzienaudio.com/h/mhroth/asdf/Edp2G", + "user": { + "linkage": { + "id": "mhroth", + "type": "user" + }, + "self": "https://enzienaudio.com/h/mhroth" + } + }, + "type": "job" + }, + "included": [ + { + "filename": "file.c.zip", + "generator": "c", + "id": "mhroth/asdf/Edp2G/c", + "links": { + "self": "https://enzienaudio.com/h/mhroth/asdf/Edp2G/c/file.c.zip" + }, + "mime": "application/zip", + "type": "file" + } + ], + "warnings": [], + "meta": { + "token": "11AS0qPRmjTUHEMSovPEvzjodnzB1xaz" + } + } + """ + reply_json = r.json() + if args.verbose: + print json.dumps( + reply_json, + sort_keys=True, + indent=2, + separators=(",", ": ")) + + # update the api token, if present + if "token" in reply_json.get("meta",{}) and not args.x: + if not os.path.exists(os.path.dirname(token_path)): + os.makedirs(os.path.dirname(token_path)) # ensure that the .heavy directory exists + with open(token_path, "w") as f: + f.write(reply_json["meta"]["token"]) + os.chmod(token_path, stat.S_IRUSR | stat.S_IWUSR) # force rw------- permissions on the file + + # print any warnings + for x in r_json["warnings"]: + print "{0}Warning:{1} {2}".format(Colours.yellow, Colours.end, x["detail"]) + + # check for errors + if len(r_json.get("errors",[])) > 0: + shutil.rmtree(temp_dir) # clean up the temporary directory + for x in r_json["errors"]: + print "{0}Error:{1} {2}".format(Colours.red, Colours.end, x["detail"]) + sys.exit(1) + return + + # retrieve all requested files + for i,g in enumerate(args.gen): + file_url = __get_file_url_for_generator(reply_json, g) + if file_url is not None and (len(args.out) > i or args.b): + r = requests.get( + file_url, + cookies={"token": reply_json["meta"]["token"]}, + verify=False if args.noverify else True) + r.raise_for_status() + + # write the reply to a temporary file + c_zip_path = os.path.join(temp_dir, "archive.{0}.zip".format(g)) + with open(c_zip_path, "wb") as f: + f.write(r.content) + + # unzip the files to where they belong + if args.b: + target_dir = os.path.join(os.path.abspath(os.path.expanduser(args.out[0])), g) + else: + target_dir = os.path.abspath(os.path.expanduser(args.out[i])) + if not os.path.exists(target_dir): + os.makedirs(target_dir) # ensure that the output directory exists + __unzip(c_zip_path, target_dir) + + print "{0} files placed in {1}".format(g, target_dir) + else: + print "{0}Warning:{1} {2} files could not be retrieved.".format( + Colours.yellow, Colours.end, + g) + + # delete the temporary directory + shutil.rmtree(temp_dir) + + print "Job URL", reply_json["data"]["links"]["self"] + print "Total request time: {0}ms".format(int(1000.0*(time.time()-tick))) + + sys.exit(0) + +def __get_file_url_for_generator(json_api, g): + """Returns the file link for a specific generator. + Returns None if no link could be found. + """ + for i in json_api["included"]: + if g == i["generator"]: + return i["links"]["self"] + return None # by default, return None + + + +if __name__ == "__main__": + main()