void cPack_onMessage(HvBase *_c, ControlPack *o, int letIn, const HvMessage *const m, void (*sendMessage)(HvBase *, int, const HvMessage *const)) { // ensure let index is less than number elements in internal msg int numElements = msg_getNumElements(o->msg); switch (letIn) { case 0: { // first inlet stores all values of input msg and triggers an output for (int i = hv_min_i(numElements, msg_getNumElements(m))-1; i >= 0; --i) { switch (msg_getType(m, i)) { case HV_MSG_FLOAT: msg_setFloat(o->msg, i, msg_getFloat(m, i)); break; case HV_MSG_SYMBOL: case HV_MSG_HASH: msg_setHash(o->msg, i, msg_getHash(m, i)); break; default: break; } } msg_setTimestamp(o->msg, msg_getTimestamp(m)); sendMessage(_c, 0, o->msg); break; } default: { // rest of inlets just store values switch (msg_getType(m, 0)) { case HV_MSG_FLOAT: msg_setFloat(o->msg, letIn, msg_getFloat(m, 0)); break; case HV_MSG_SYMBOL: case HV_MSG_HASH: msg_setHash(o->msg, letIn, msg_getHash(m, 0)); break; default: break; } break; } } }
void sTabwrite_onMessage(HvBase *_c, SignalTabwrite *o, int letIn, const HvMessage *const m, void (*sendMessage)(HvBase *, int, const HvMessage *const)) { switch (letIn) { // inlet 0 is the signal inlet case 1: { switch (msg_getType(m,0)) { case BANG: o->head = 0; break; case FLOAT: { o->head = (msg_getFloat(m,0) >= 0.0f) ? (hv_uint32_t) msg_getFloat(m,0) : HV_TABWRITE_STOPPED; break; } case SYMBOL: { if (msg_compareSymbol(m, 0, "stop")) { o->head = HV_TABWRITE_STOPPED; } break; } default: break; } break; } case 2: { if (msg_isHashLike(m,0)) { o->table = ctx_getTableForHash(_c, msg_getHash(m,0)); } break; } default: break; } }
void cTabwrite_onMessage(HvBase *_c, ControlTabwrite *o, int letIn, const HvMessage *const m, void (*sendMessage)(HvBase *, int, const HvMessage *const)) { switch (letIn) { case 0: { if (msg_isFloat(m,0) && o->table != NULL) { hTable_getBuffer(o->table)[o->x] = msg_getFloat(m,0); // update Y value } break; } case 1: { if (msg_isFloat(m,0) && o->table != NULL) { const int x = (int) msg_getFloat(m,0); if (x >= 0 && x < hTable_getSize(o->table)) { o->x = x; // update X value } } break; } case 2: { if (msg_isHashLike(m,0)) { o->table = ctx_getTableForHash(_c,msg_getHash(m,0)); // update table } break; } default: return; } }
void cDelay_onMessage(HvBase *_c, ControlDelay *o, int letIn, const HvMessage *const m, void (*sendMessage)(HvBase *, int, const HvMessage *const)) { switch (letIn) { case 0: { if (msg_compareSymbol(m, 0, "flush")) { // send all messages immediately for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) { HvMessage *n = o->msgs[i]; if (n != NULL) { msg_setTimestamp(n, msg_getTimestamp(m)); // update the timestamp to now sendMessage(_c, 0, n); // send the message ctx_cancelMessage(_c, n, sendMessage); // then clear it // NOTE(mhroth): there may be a problem here if a flushed message causes a clear message to return // to this object in the same step } } hv_memset(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *)); } else if (msg_compareSymbol(m, 0, "clear")) { // cancel (clear) all (pending) messages for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) { HvMessage *n = o->msgs[i]; if (n != NULL) { ctx_cancelMessage(_c, n, sendMessage); } } hv_memset(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *)); } else { hv_uint32_t ts = msg_getTimestamp(m); msg_setTimestamp((HvMessage *) m, ts+o->delay); // update the timestamp to set the delay int i; for (i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) { if (o->msgs[i] == NULL) { o->msgs[i] = ctx_scheduleMessage(_c, m, sendMessage, 0); break; } } hv_assert(i < __HV_DELAY_MAX_MESSAGES); // scheduled message limit reached msg_setTimestamp((HvMessage *) m, ts); // return to the original timestamp } break; } case 1: { if (msg_isFloat(m,0)) { // set delay in milliseconds o->delay = ctx_millisecondsToSamples(_c,msg_getFloat(m,0)); } break; } case 2: { if (msg_isFloat(m,0)) { // set delay in samples o->delay = (hv_uint32_t) msg_getFloat(m,0); } break; } default: break; } }
void sBiquad_k_onMessage(SignalBiquad_k *o, int letIn, const HvMessage *const m) { if (msg_isFloat(m,0)) { switch (letIn) { case 1: o->b0 = msg_getFloat(m,0); break; case 2: o->b1 = msg_getFloat(m,0); break; case 3: o->b2 = msg_getFloat(m,0); break; case 4: o->a1 = msg_getFloat(m,0); break; case 5: o->a2 = msg_getFloat(m,0); break; default: return; } sBiquad_k_updateCoefficients(o); } }
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 HV_MSG_BANG: { HvMessage *n = HV_MESSAGE_ON_STACK(1); if (o->e.type == HV_MSG_FLOAT) msg_initWithFloat(n, msg_getTimestamp(m), o->e.data.f); else if (o->e.type == HV_MSG_HASH) msg_initWithHash(n, msg_getTimestamp(m), o->e.data.h); else return; sendMessage(_c, 0, n); break; } case HV_MSG_FLOAT: { o->e.type = HV_MSG_FLOAT; o->e.data.f = msg_getFloat(m,0); sendMessage(_c, 0, m); break; } case HV_MSG_SYMBOL: case HV_MSG_HASH: { o->e.type = HV_MSG_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 HV_MSG_FLOAT: { o->e.type = HV_MSG_FLOAT; o->e.data.f = msg_getFloat(m,0); break; } case HV_MSG_SYMBOL: case HV_MSG_HASH: { o->e.type = HV_MSG_HASH; o->e.data.h = msg_getHash(m,0); break; } default: break; } } default: return; } }
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; } }
void cSlice_onMessage(HvBase *_c, ControlSlice *o, int letIn, const HvMessage *const m, void (*sendMessage)(HvBase *, int, const HvMessage *const)) { switch (letIn) { case 0: { // if the start point is greater than the number of elements in the source message, do nothing if (o->i < msg_getNumElements(m)) { int x = msg_getNumElements(m) - o->i; // number of elements in the new message if (o->n > 0) x = hv_min_i(x, o->n); HvMessage *n = HV_MESSAGE_ON_STACK(x); msg_init(n, x, msg_getTimestamp(m)); hv_memcpy(&n->elem, &m->elem+o->i, x*sizeof(Element)); sendMessage(_c, 0, n); } else { // if nothing can be sliced, send a bang out of the right outlet HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithBang(n, msg_getTimestamp(m)); sendMessage(_c, 1, n); } break; } case 1: { if (msg_isFloat(m,0)) { o->i = (int) msg_getFloat(m,0); if (msg_isFloat(m,1)) { o->n = (int) msg_getFloat(m,1); } } break; } case 2: { if (msg_isFloat(m,0)) { o->n = (int) msg_getFloat(m,0); } break; } default: break; } }
void cTabread_onMessage(HvBase *_c, ControlTabread *o, int letIn, const HvMessage *const m, void (*sendMessage)(HvBase *, int, const HvMessage *const)) { switch (letIn) { case 0: { if (msg_isFloat(m,0) && msg_getFloat(m,0) >= 0.0f && o->table != NULL) { const hv_uint32_t x = (hv_uint32_t) msg_getFloat(m,0); if (x < hTable_getSize(o->table)) { HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, msg_getTimestamp(m), hTable_getBuffer(o->table)[x]); sendMessage(_c, 0, n); } } break; } case 1: { if (msg_isHashLike(m,0)) { o->table = ctx_getTableForHash(_c, msg_getHash(m,0)); } break; } default: return; } }
void sLine_onMessage(HvBase *_c, SignalLine *o, int letIn, const HvMessage * const m, void *sendMessage) { if (msg_isFloat(m,0)) { if (msg_isFloat(m,1)) { // new ramp int n = ctx_millisecondsToSamples(_c, msg_getFloat(m,1)); #if HV_SIMD_AVX float x = (o->n[1] > 0) ? (o->x[7] + (o->m[7]/8.0f)) : o->t[7]; // current output value float s = (msg_getFloat(m,0) - x) / ((float) n); // slope per sample o->n = _mm_set_epi32(n-3, n-2, n-1, n); o->x = _mm256_set_ps(x+7.0f*s, x+6.0f*s, x+5.0f*s, x+4.0f*s, x+3.0f*s, x+2.0f*s, x+s, x); o->m = _mm256_set1_ps(8.0f*s); o->t = _mm256_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_SSE float x = (o->n[1] > 0) ? (o->x[3] + (o->m[3]/4.0f)) : o->t[3]; float s = (msg_getFloat(m,0) - x) / ((float) n); // slope per sample o->n = _mm_set_epi32(n-3, n-2, n-1, n); o->x = _mm_set_ps(x+3.0f*s, x+2.0f*s, x+s, x); o->m = _mm_set1_ps(4.0f*s); o->t = _mm_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_NEON float x = (o->n[3] > 0) ? (o->x[3] + (o->m[3]/4.0f)) : o->t[3]; float s = (msg_getFloat(m,0) - x) / ((float) n); o->n = (int32x4_t) {n, n-1, n-2, n-3}; o->x = (float32x4_t) {x, x+s, x+2.0f*s, x+3.0f*s}; o->m = vdupq_n_f32(4.0f*s); o->t = vdupq_n_f32(msg_getFloat(m,0)); #else // HV_SIMD_NONE o->x = (o->n > 0) ? (o->x + o->m) : o->t; // new current value o->n = n; // new distance to target o->m = (msg_getFloat(m,0) - o->x) / ((float) n); // slope per sample o->t = msg_getFloat(m,0); #endif } else { // Jump to value #if HV_SIMD_AVX o->n = _mm_setzero_si128(); o->x = _mm256_set1_ps(msg_getFloat(m,0)); o->m = _mm256_setzero_ps(); o->t = _mm256_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_SSE o->n = _mm_setzero_si128(); o->x = _mm_set1_ps(msg_getFloat(m,0)); o->m = _mm_setzero_ps(); o->t = _mm_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_NEON o->n = vdupq_n_s32(0); o->x = vdupq_n_f32(0.0f); o->m = vdupq_n_f32(0.0f); o->t = vdupq_n_f32(0.0f); #else // HV_SIMD_NONE o->n = 0; o->x = msg_getFloat(m,0); o->m = 0.0f; o->t = msg_getFloat(m,0); #endif } } else if (msg_compareSymbol(m,0,"stop")) { // Stop line at current position #if HV_SIMD_AVX // note o->n[1] is a 64-bit integer; two packed 32-bit ints. We only want to know if the high int is positive, // which can be done simply by testing the long int for positiveness. float x = (o->n[1] > 0) ? (o->x[7] + (o->m[7]/8.0f)) : o->t[7]; o->n = _mm_setzero_si128(); o->x = _mm256_set1_ps(x); o->m = _mm256_setzero_ps(); o->t = _mm256_set1_ps(x); #elif HV_SIMD_SSE float x = (o->n[1] > 0) ? (o->x[3] + (o->m[3]/4.0f)) : o->t[3]; o->n = _mm_setzero_si128(); o->x = _mm_set1_ps(x); o->m = _mm_setzero_ps(); o->t = _mm_set1_ps(x); #elif HV_SIMD_NEON float x = (o->n[3] > 0) ? (o->x[3] + (o->m[3]/4.0f)) : o->t[3]; o->n = vdupq_n_s32(0); o->x = vdupq_n_f32(x); o->m = vdupq_n_f32(0.0f); o->t = vdupq_n_f32(x); #else // HV_SIMD_NONE o->n = 0; o->x += o->m; o->m = 0.0f; o->t = o->x; #endif } }
float hv_msg_getFloat(const HvMessage *const m, int i) { return msg_getFloat(m,i); }