HvMessage *mp_addMessage(MessagePool *mp, const HvMessage *m) { const hv_size_t b = msg_getSize(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); hv_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) && "The message pool buffer size has been exceeded. The context cannot store more messages. " "Try using the new_with_options() initialiser with a larger pool size (default is 10KB)."); for (hv_size_t j = mp->bufferIndex; j < newIndex; j += chunkSize) { ml_push(ml, mp->buffer + j); // 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; } }
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; } }
hv_size_t mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB) { hv_assert(poolSizeKB > 0); q->head = NULL; q->tail = NULL; q->pool = NULL; return mp_init(&q->mp, poolSizeKB); }
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; } }
static MessageNode *mq_getOrCreateNodeFromPool(MessageQueue *q) { if (q->pool == NULL) { // if necessary, create a new empty node q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode)); hv_assert(q->pool != NULL); q->pool->next = NULL; } MessageNode *node = q->pool; q->pool = q->pool->next; return node; }
hv_size_t mp_init(MessagePool *mp, hv_size_t numKB) { mp->bufferSize = numKB * 1024; mp->buffer = (char *) hv_malloc(mp->bufferSize); hv_assert(mp->buffer != NULL); 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; }
/** 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)); hv_assert(n != NULL); } n->p = (char *) p; n->next = ml->head; ml->head = n; // push to the front of the queue }
static void sBiquad_k_updateCoefficients(SignalBiquad_k *const o) { #if 0 // inspect the filter coefficients to ensure that the filter is stable // 1/((1-a*z^-1) * (1-b*z^-1)) float k = (o->a1*o->a1) - (4.0f*o->a2); float l = hv_sqrt_f(hv_abs_f(k)); float m_alpha = 0.0f; float m_beta = 0.0f; if (k < 0.0f) { // alpha is complex float r_alpha = o->a1 * 0.5f; float i_alpha = l * 0.5f; m_alpha = (r_alpha*r_alpha + i_alpha*i_alpha); // |alpha|^2 float r_beta = (o->a2 * r_alpha) / m_alpha; float i_beta = (o->a2 * -i_alpha) / m_alpha; m_alpha = hv_sqrt_f(m_alpha); m_beta = hv_sqrt_f(r_beta*r_beta + i_beta*i_beta); } else { // alpha is real float alpha = (o->a1 + l) * 0.5f; float beta = o->a2 / alpha; m_alpha = hv_abs_f(alpha); m_beta = hv_abs_f(beta); } hv_assert(m_alpha < 1.0f); hv_assert(m_beta < 1.0f); #endif // calculate all filter coefficients in the double domain #if HV_SIMD_AVX || HV_SIMD_SSE || HV_SIMD_NEON double b0 = (double) o->b0; double b1 = (double) o->b1; double b2 = (double) o->b2; double a1 = (double) -o->a1; double a2 = (double) -o->a2; double coeffs[4][8] = { { 0, 0, 0, b0, b1, b2, a1, a2 }, { 0, 0, b0, b1, b2, 0, a2, 0 }, { 0, b0, b1, b2, 0, 0, 0, 0 }, { b0, b1, b2, 0, 0, 0, 0, 0 }, }; for (int i = 0; i < 8; i++) { coeffs[1][i] += a1*coeffs[0][i]; coeffs[2][i] += a1*coeffs[1][i] + a2*coeffs[0][i]; coeffs[3][i] += a1*coeffs[2][i] + a2*coeffs[1][i]; } #if HV_SIMD_AVX || HV_SIMD_SSE o->coeff_xp3 = _mm_set_ps((float) coeffs[3][0], (float) coeffs[2][0], (float) coeffs[1][0], (float) coeffs[0][0]); o->coeff_xp2 = _mm_set_ps((float) coeffs[3][1], (float) coeffs[2][1], (float) coeffs[1][1], (float) coeffs[0][1]); o->coeff_xp1 = _mm_set_ps((float) coeffs[3][2], (float) coeffs[2][2], (float) coeffs[1][2], (float) coeffs[0][2]); o->coeff_x0 = _mm_set_ps((float) coeffs[3][3], (float) coeffs[2][3], (float) coeffs[1][3], (float) coeffs[0][3]); o->coeff_xm1 = _mm_set_ps((float) coeffs[3][4], (float) coeffs[2][4], (float) coeffs[1][4], (float) coeffs[0][4]); o->coeff_xm2 = _mm_set_ps((float) coeffs[3][5], (float) coeffs[2][5], (float) coeffs[1][5], (float) coeffs[0][5]); o->coeff_ym1 = _mm_set_ps((float) coeffs[3][6], (float) coeffs[2][6], (float) coeffs[1][6], (float) coeffs[0][6]); o->coeff_ym2 = _mm_set_ps((float) coeffs[3][7], (float) coeffs[2][7], (float) coeffs[1][7], (float) coeffs[0][7]); #else // HV_SIMD_NEON o->coeff_xp3 = (float32x4_t) {(float) coeffs[0][0], (float) coeffs[1][0], (float) coeffs[2][0], (float) coeffs[3][0]}; o->coeff_xp2 = (float32x4_t) {(float) coeffs[0][1], (float) coeffs[1][1], (float) coeffs[2][1], (float) coeffs[3][1]}; o->coeff_xp1 = (float32x4_t) {(float) coeffs[0][2], (float) coeffs[1][2], (float) coeffs[2][2], (float) coeffs[3][2]}; o->coeff_x0 = (float32x4_t) {(float) coeffs[0][3], (float) coeffs[1][3], (float) coeffs[2][3], (float) coeffs[3][3]}; o->coeff_xm1 = (float32x4_t) {(float) coeffs[0][4], (float) coeffs[1][4], (float) coeffs[2][4], (float) coeffs[3][4]}; o->coeff_xm2 = (float32x4_t) {(float) coeffs[0][5], (float) coeffs[1][5], (float) coeffs[2][5], (float) coeffs[3][5]}; o->coeff_ym1 = (float32x4_t) {(float) coeffs[0][6], (float) coeffs[1][6], (float) coeffs[2][6], (float) coeffs[3][6]}; o->coeff_ym2 = (float32x4_t) {(float) coeffs[0][7], (float) coeffs[1][7], (float) coeffs[2][7], (float) coeffs[3][7]}; #endif #endif // NOTE(mhroth): not necessary to calculate any coefficients for HV_SIMD_NONE case }
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); }