/* Expand a spline segment into a buffer */ static int expandSpline(AS3_Val *modPoint, float *buffer, int frames) { double y0Arg, y1Arg, y2Arg, y3Arg; float y0, y1, y2, y3; float p, incr; int count; AS3_ObjectValue(*modPoint, "y0:DoubleType, y1:DoubleType, y2:DoubleType, y3:DoubleType", &y0Arg, &y1Arg, &y2Arg, &y3Arg); y0 = (float) y0Arg; y1 = (float) y1Arg; y2 = (float) y2Arg; y3 = (float) y3Arg; incr = 1 / (float) frames; count = frames; p = 0; // Optimize continuous, linear, and cubic modes if (y0 == 0 && y1 == 0 && y2 == 0 && y3 == 0 ) { // All values are zero memset(buffer, 0, frames * 4); } else if (y0 == y1 && y1 == y2 && y2 == y3) { // All values are the same while (count--) { *buffer++ = y1; } } else if (y0 == y1 && y2 == y3) { // Linear interpolation while (count--) { *buffer++ = interpolate(y1, y2, p); p += incr; } } else { // This is a full spline segment // Loop over the whole segment and calc instantaneous spline values with cubic interpolation while (count--) { *buffer++ = cubicInterpolate(y0, y1, y2, y3, p); p += incr; } } return 0; }
// Go check a Flash event queue for events SDL should be aware of! void FLASH_PumpEvents(_THIS) { if (!FLASH_EMPTY_PARAMS) FLASH_EMPTY_PARAMS = AS3_Array(""); // Event Vars AS3_Val mouseEvent, mouseEvents, mousePosition, keyboardEvent, keyboardEvents; int buttonState, rawKeyboardEvent, scanCode, keyState; SDL_keysym keysym; mousePosition = AS3_CallS( "pumpMousePosition", FLASH_EVENT_MANAGER_OBJECT, FLASH_EMPTY_PARAMS ); mouseEvents = AS3_CallS( "pumpMouseEvents", FLASH_EVENT_MANAGER_OBJECT, FLASH_EMPTY_PARAMS ); keyboardEvents = AS3_CallS( "pumpKeyEvents", FLASH_EVENT_MANAGER_OBJECT, FLASH_EMPTY_PARAMS ); // Mouse Position if (mousePosition) { AS3_ObjectValue( mousePosition, "x:IntType, y:IntType", &FLASH_mouseX, &FLASH_mouseY ); SDL_PrivateMouseMotion( 0, 0, FLASH_mouseX, FLASH_mouseY ); } // Mouse Click Events while( AS3_IntValue(AS3_GetS(mouseEvents, "size")) > 0 ) { mouseEvent = AS3_CallS( "dequeue", mouseEvents, FLASH_EMPTY_PARAMS ); buttonState = AS3_IntValue( mouseEvent )? SDL_PRESSED: SDL_RELEASED; SDL_PrivateMouseButton(buttonState, SDL_BUTTON_LEFT, FLASH_mouseX, FLASH_mouseY); } // Keyboard Events while( AS3_IntValue(AS3_GetS(keyboardEvents, "size")) > 0 ) { keyboardEvent = AS3_CallS( "dequeue", keyboardEvents, FLASH_EMPTY_PARAMS ); rawKeyboardEvent = AS3_IntValue( keyboardEvent ); scanCode = rawKeyboardEvent & 0xFF; // Packed event format: 9th bit for press/release, lower 8 bits for scan code keyState = rawKeyboardEvent >> 8; SDL_PrivateKeyboard(keyState, TranslateKey(scanCode, &keysym)); } }
static AS3_Val biquad(void *self, AS3_Val args) { int bufferPosition; int channels; int frames; int count; float *buffer; int stateBufferPosition; float *stateBuffer; AS3_Val coeffs; // coefficients object double a0d, a1d, a2d, b0d, b1d, b2d; // doubles from object float a0, a1, a2, b0, b1, b2; // filter coefficients float lx, ly, lx1, lx2, ly1, ly2; // left delay line float rx, ry, rx1, rx2, ry1, ry2; // right delay line // Extract args AS3_ArrayValue(args, "IntType, IntType, IntType, IntType, AS3ValType", &bufferPosition, &stateBufferPosition, &channels, &frames, &coeffs); buffer = (float *) bufferPosition; stateBuffer = (float *) stateBufferPosition; // Extract filter coefficients from object AS3_ObjectValue(coeffs, "a0:DoubleType, a1:DoubleType, a2:DoubleType, b0:DoubleType, b1:DoubleType, b2:DoubleType", &a0d, &a1d, &a2d, &b0d, &b1d, &b2d); // Cast to floats a0 = (float) a0d; a1 = (float) a1d; a2 = (float) a2d; b0 = (float) b0d; b1 = (float) b1d; b2 = (float) b2d; // Make sure we recieved all the correct coefficients // sprintf(trace, "Biquad a0=%f a1=%f a2=%f b0=%f b1=%f b2=%f", a0, a1, a2, b0, b1, b2); // sztrace(trace); count = frames; if (channels == 1) { lx1 = *stateBuffer; lx2 = *(stateBuffer+1); ly1 = *(stateBuffer+2); ly2 = *(stateBuffer+3); while (count--) { lx = *buffer + 1e-15 - 1e-15; // input with denormals zapped ly = lx*b0 + lx1*b1 + lx2*b2 - ly1*a1 - ly2*a2; lx2 = lx1; lx1 = lx; ly2 = ly1; ly1 = ly; *buffer++ = ly; // output } *stateBuffer = lx1; *(stateBuffer+1) = lx2; *(stateBuffer+2) = ly1; *(stateBuffer+3) = ly2; } else if (channels == 2) { lx1 = *stateBuffer; rx1 = *(stateBuffer+1); lx2 = *(stateBuffer+2); rx2 = *(stateBuffer+3); ly1 = *(stateBuffer+4); ry1 = *(stateBuffer+5); ly2 = *(stateBuffer+6); ry2 = *(stateBuffer+7); while (count--) { lx = *buffer + 1e-15 - 1e-15; // left input ly = lx*b0 + lx1*b1 + lx2*b2 - ly1*a1 - ly2*a2; lx2 = lx1; lx1 = lx; ly2 = ly1; ly1 = ly; *buffer++ = ly; // left output rx = *buffer + 1e-15 - 1e-15; // right input ry = rx*b0 + rx1*b1 + rx2*b2 - ry1*a1 - ry2*a2; rx2 = rx1; rx1 = rx; ry2 = ry1; ry1 = ry; *buffer++ = ry; // right output } *stateBuffer = lx1; *(stateBuffer+1) = rx1; *(stateBuffer+2) = lx2; *(stateBuffer+3) = rx2; *(stateBuffer+4) = ly1; *(stateBuffer+5) = ry1; *(stateBuffer+6) = ly2; *(stateBuffer+7) = ry2; } return 0; }
static AS3_Val delay(void *self, AS3_Val args) { int bufferPosition; int channels; int frames; int count; float *buffer; int ringBufferPosition; float *ringBuffer; AS3_Val settings; int length; double feedbackArg; float feedback; double dryMixArg; float dryMix; double wetMixArg; float wetMix; int offset = 0; float echo; float *echoPointer; // Extract args AS3_ArrayValue(args, "IntType, IntType, IntType, IntType, AS3ValType", &bufferPosition, &ringBufferPosition, &channels, &frames, &settings); AS3_ObjectValue(settings, "length:IntType, dryMix:DoubleType, wetMix:DoubleType, feedback:DoubleType", &length, &dryMixArg, &wetMixArg, &feedbackArg); // Cast arguments to the needed types buffer = (float *) bufferPosition; ringBuffer = (float *) ringBufferPosition; dryMix = (float) dryMixArg; wetMix = (float) wetMixArg; feedback = (float) feedbackArg; // Show params // sprintf(trace, "Echo length=%d, dry=%f, wet=%f, fb=%f", length, dryMix, wetMix, feedback); // sztrace(trace); count = frames * channels; while (count--) { if (offset > length) { offset = 0; } echoPointer = ringBuffer + offset; echo = *echoPointer; *echoPointer = *buffer + echo*feedback; *buffer = *buffer * dryMix + echo * wetMix + 1e-15 - 1e-15; buffer++; offset++; } // Shift the memory so that the echo pointer offset is the start of the buffer int ringSize = length * channels * sizeof(float); int firstChunkSize = offset * channels * sizeof(float); int secondChunkSize = ringSize - firstChunkSize; float *temp = (float *) malloc(ringSize); // copy offset-end -> start of temp buffer memcpy(temp, ringBuffer + offset, secondChunkSize); // copy start-offset -> second half of temp buffer memcpy(temp + offset, ringBuffer, firstChunkSize); // copy temp buffer back to ringbuffer memcpy(ringBuffer, temp, ringSize); free(temp); return 0; }
/** * Scan in a wavetable. Wavetable should be at least one longer than the table size. */ static AS3_Val wavetableIn(void *self, AS3_Val args) { AS3_Val settings; int bufferPosition; int channels; int frames; float *buffer; int sourceBufferPosition; float *sourceBuffer; double phaseArg; float phase; double phaseAddArg; float phaseAdd; double phaseResetArg; float phaseReset; int tableSize; int count; int intPhase; float *wavetablePosition; float *scratch; double y1Arg, y2Arg; float y1, y2; float fractional, fractionalIncrement, instantBend; AS3_ArrayValue(args, "IntType, IntType, IntType, IntType, AS3ValType", &bufferPosition, &sourceBufferPosition, &channels, &frames, &settings); AS3_ObjectValue(settings, "tableSize:IntType, phase:DoubleType, phaseAdd:DoubleType, phaseReset:DoubleType, y1:DoubleType, y2:DoubleType", &tableSize, &phaseArg, &phaseAddArg, &phaseResetArg, &y1Arg, &y2Arg); buffer = (float *) bufferPosition; sourceBuffer = (float *) sourceBufferPosition; phaseAdd = (float) phaseAddArg * tableSize; // num source frames to add per output frames phase = (float) phaseArg * tableSize; // translate into a frame count into the table phaseReset = (float) phaseResetArg * tableSize; y1 = (float) y1Arg; y2 = (float) y2Arg; // Expand the pitch modulation into scratch // expandLine(scratch1, y1, y2, frames); // draws spline segment into scratch1 // scratch = (float *) scratch1; // Make sure we got everything right //sprintf(trace, "Wavetable size=%d phase=%f phaseAdd=%f y1=%f y2=%f", tableSize, phase, phaseAdd, y1, y2); //sztrace(trace); count=frames; fractional = 0.0; fractionalIncrement = 1 / (float) frames; if (channels == 1) { while (count--) { while (phase >= tableSize) { if (phaseReset == -1) { // no looping! return 0; } else { // wrap phase to the loop point phase -= tableSize; phase += phaseReset; } } intPhase = (int) phase; // int phase wavetablePosition = sourceBuffer + intPhase; *buffer++ = interpolate(*wavetablePosition, *(wavetablePosition+1), phase - intPhase); // Increment phase by adjusting phaseAdd for instantaneous pitch bend instantBend = interpolate(y1, y2, fractional); fractional += fractionalIncrement; phase += phaseAdd * shiftToFreq(instantBend); } } else if (channels == 2 ) { while (count--) { while (phase >= tableSize) { if (phaseReset == -1) { // no looping! return 0; } else { // wrap phase to the loop point phase -= tableSize; phase += phaseReset; } } intPhase = ((int)(phase*0.5))*2; // int phase, round to even frames, for each stereo frame pair wavetablePosition = sourceBuffer + intPhase; *buffer++ = interpolate(*wavetablePosition, *(wavetablePosition+2), phase - intPhase); *buffer++ = interpolate(*(wavetablePosition+1), *(wavetablePosition+3), phase - intPhase); // Increment phase by adjusting phaseAdd for instantaneous pitch bend instantBend = interpolate(y1, y2, fractional); fractional += fractionalIncrement; phase += phaseAdd * shiftToFreq(instantBend); } } // Scale back down to a factor, and write the final phase value back to AS3 phase /= tableSize; AS3_Set(settings, AS3_String("phase"), AS3_Number(phase)); return 0; }