#include "DspPhasor.h"
#include "PdGraph.h"
#define SHORT_TO_FLOAT_RATIO 0.0000152590219f
message::Object *DspPhasor::new_object(pd::Message *init_message, PdGraph *graph) {
return new DspPhasor(init_message, graph);
}
DspPhasor::DspPhasor(pd::Message *init_message, PdGraph *graph) : DspObject(2, 2, 0, 1, graph) {
pd::Message *message = PD_MESSAGE_ON_STACK(1);
message->from_timestamp_and_float(0.0, init_message->is_float(0) ? init_message->get_float(0) : 0.0f);
process_message(0, message);
process_function = &processScalar;
process_functionNoMessage = &processScalar;
}
DspPhasor::~DspPhasor() {
}
string DspPhasor::toString() {
char str[snprintf(NULL, 0, "%s %g", get_object_label(), frequency)+1];
snprintf(str, sizeof(str), "%s %g", get_object_label(), frequency);
return string(str);
}
void DspPhasor::onInletConnectionUpdate(unsigned int inlet_index) {
process_function = incomingDspConnections[0].empty() ? &processScalar : &processSignal;
}
void DspPhasor::process_message(int inlet_index, pd::Message *message) {
switch (inlet_index) {
case 0: { if (message->is_float(0)) {
frequency = message->get_float(0);
#if __SSE3__
float sampleStep = frequency * 65536.0f / graph->get_sample_rate();
short s = (short) sampleStep; inc = _mm_set1_pi16(4*s);
#endif }
break;
}
case 1: { break;
}
default: break;
}
}
void DspPhasor::processSignal(DspObject *dspObject, int fromIndex, int n4) {
DspPhasor *d = reinterpret_cast<DspPhasor *>(dspObject);
#if __SSE3__
float *input = d->dspBufferAtInlet[0];
float *output = d->dspBufferAtOutlet[0];
__m64 indicies = d->indicies;
static __m128 constVec = _mm_set1_ps(SHORT_TO_FLOAT_RATIO);
static __m128 sampVec = _mm_set1_ps(65536.0f/d->graph->get_sample_rate());
while (n4) {
__m64 inc = _mm_cvtps_pi16(_mm_mul_ps(_mm_load_ps(input),sampVec));
inc = _mm_add_pi16(_mm_add_pi16(_mm_add_pi16(inc,_mm_slli_si64(inc,16)),
_mm_slli_si64(inc,32)),_mm_slli_si64(inc,48));
indicies = _mm_add_pi16(_mm_set1_pi16(_mm_extract_pi16(indicies,3)), inc);
_mm_store_ps(output,_mm_mul_ps(_mm_cvtpu16_ps(indicies),constVec));
input += 4;
output += 4;
n4 -= 4;
}
d->indicies = indicies;
#else
#endif
}
void DspPhasor::processScalar(DspObject *dspObject, int fromIndex, int toIndex) {
DspPhasor *d = reinterpret_cast<DspPhasor *>(dspObject);
#if __SSE3__
int n = toIndex - fromIndex;
float *output = d->dspBufferAtOutlet[0]+fromIndex;
__m64 inc = d->inc;
short s = _mm_extract_pi16(inc,0) >> 2; static __m128 constVec = _mm_set1_ps(SHORT_TO_FLOAT_RATIO);
unsigned short idx;
__m64 indicies;
switch (fromIndex & 0x3) {
case 1: {
idx = _mm_extract_pi16(d->indicies,0); *output++ = ((float) idx) * SHORT_TO_FLOAT_RATIO; idx += s; --n;
}
case 2: *output++ = ((float) idx) * SHORT_TO_FLOAT_RATIO; idx += s; --n;
case 3: {
*output++ = ((float) idx) * SHORT_TO_FLOAT_RATIO; idx += s; --n;
indicies = _mm_set_pi16(idx+3*s, idx+2*s, idx+s, idx);
break;
}
default: indicies = d->indicies; break;
}
int n4 = n & 0xFFFFFFFC; while (n4) {
_mm_store_ps(output, _mm_mul_ps(_mm_cvtpu16_ps(indicies),constVec));
indicies = _mm_add_pi16(indicies, inc);
output += 4;
n4 -= 4;
}
switch (n & 0x3) {
case 3: {
idx = _mm_extract_pi16(d->indicies,3);
*output++ = ((float) idx) * SHORT_TO_FLOAT_RATIO; idx += s;
}
case 2: *output++ = ((float) idx) * SHORT_TO_FLOAT_RATIO; idx += s;
case 1: {
*output++ = ((float) idx) * SHORT_TO_FLOAT_RATIO; idx += s;
d->indicies = _mm_set_pi16(idx+3*s, idx+2*s, idx+s, idx);
break;
}
default: d->indicies = indicies; break;
}
#else
#endif
}