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 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 *table = ctx_getTableForHash(_c, msg_getHash(m,1)); if (table != NULL) { if (msg_compareSymbol(m, 2, "length")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getLength(table)); } else if (msg_compareSymbol(m, 2, "size")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(table)); } else if (msg_compareSymbol(m, 2, "head")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(table)); } else return; } else return; } else return; sendMessage(_c, 0, n); }
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 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 cPrint_onMessage(HvBase *_c, const HvMessage *const m, const char *name) { if (Base(_c)->printHook != NULL) { char *s = msg_toString(m); Base(_c)->printHook(((double) msg_getTimestamp(m))/ctx_getSampleRate(_c), name, s, ctx_getUserData(_c)); hv_free(s); } }
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 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 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; }
double hv_msg_getTimestamp(const HvMessage *const m) { return msg_getTimestamp(m); }
void sSample_onMessage(HvBase *_c, SignalSample *o, int letIndex, const HvMessage *m) { o->i = msg_getTimestamp(m); }