/* 7th order interpolation. * Returns number of samples processed (usually fluid_bufsize but could be * smaller if end of sample occurs). */ public static int fluid_dsp_float_interpolate_7th_order(fluid_voice voice) { ulong dsp_phase = voice.phase; ulong dsp_phase_incr;//, end_phase; float[] dsp_data = voice.sample.Data; float[] dsp_buf = voice.dsp_buf; float dsp_amp = voice.amp; float dsp_amp_incr = voice.amp_incr; uint dsp_i = 0; uint dsp_phase_index; uint start_index, end_index; float start_points0; float start_points1; float start_points2; float end_points0; float end_points1; float end_points2; float[] coeffs; bool looping; int fluid_bufsize = voice.synth.FLUID_BUFSIZE; /* Convert playback "speed" floating point value to phase index/fract * fluid_phase_set_float(dsp_phase_incr, voice.phase_incr); */ dsp_phase_incr = (((ulong)voice.phase_incr) << 32) | (uint)(((double)(voice.phase_incr) - (int)(voice.phase_incr)) * (double)FLUID_FRACT_MAX); /* add 1/2 sample to dsp_phase since 7th order interpolation is centered on * the 4th sample point * fluid_phase_incr(dsp_phase, (ulong)0x80000000); */ dsp_phase += 0x80000000; /* voice is currently looping? */ looping = ((voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_DURING_RELEASE) || (voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_UNTIL_RELEASE && voice.volenv_section < fluid_voice_envelope_index.FLUID_VOICE_ENVRELEASE)); //Debug.LogFormat("looping:{0} ", looping); /* last index before 7th interpolation point must be specially handled */ end_index = (uint)(looping ? voice.loopend - 1 : voice.end) - 3; if (voice.has_looped) /* set start_index and start point if looped or not */ { start_index = (uint)voice.loopstart; start_points0 = dsp_data[voice.loopend - 1]; start_points1 = dsp_data[voice.loopend - 2]; start_points2 = dsp_data[voice.loopend - 3]; } else { start_index = (uint)voice.start; start_points0 = dsp_data[voice.start]; /* just duplicate the start point */ start_points1 = start_points0; start_points2 = start_points0; } /* get the 3 points off the end (loop start if looping, duplicate point if end) */ if (looping) { end_points0 = dsp_data[voice.loopstart]; end_points1 = dsp_data[voice.loopstart + 1]; end_points2 = dsp_data[voice.loopstart + 2]; } else { end_points0 = dsp_data[voice.end]; end_points1 = end_points0; end_points2 = end_points0; } while (true) { //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); /* interpolate first sample point (start or loop start) if needed */ for (; dsp_phase_index == start_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)start_points2 + coeffs[1] * (float)start_points1 + coeffs[2] * (float)start_points0 + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)dsp_data[dsp_phase_index + 1] + coeffs[5] * (float)dsp_data[dsp_phase_index + 2] + coeffs[6] * (float)dsp_data[dsp_phase_index + 3]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } start_index++; /* interpolate 2nd to first sample point (start or loop start) if needed */ for (; dsp_phase_index == start_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)start_points1 + coeffs[1] * (float)start_points0 + coeffs[2] * (float)dsp_data[dsp_phase_index - 1] + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)dsp_data[dsp_phase_index + 1] + coeffs[5] * (float)dsp_data[dsp_phase_index + 2] + coeffs[6] * (float)dsp_data[dsp_phase_index + 3]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } start_index++; /* interpolate 3rd to first sample point (start or loop start) if needed */ for (; dsp_phase_index == start_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)start_points0 + coeffs[1] * (float)dsp_data[dsp_phase_index - 2] + coeffs[2] * (float)dsp_data[dsp_phase_index - 1] + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)dsp_data[dsp_phase_index + 1] + coeffs[5] * (float)dsp_data[dsp_phase_index + 2] + coeffs[6] * (float)dsp_data[dsp_phase_index + 3]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } start_index -= 2; /* set back to original start index */ /* interpolate the sequence of sample points */ for (; dsp_i < fluid_bufsize && dsp_phase_index <= end_index; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index - 3] + coeffs[1] * (float)dsp_data[dsp_phase_index - 2] + coeffs[2] * (float)dsp_data[dsp_phase_index - 1] + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)dsp_data[dsp_phase_index + 1] + coeffs[5] * (float)dsp_data[dsp_phase_index + 2] + coeffs[6] * (float)dsp_data[dsp_phase_index + 3]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } /* break out if buffer filled */ if (dsp_i >= fluid_bufsize) { break; } end_index++; /* we're now interpolating the 3rd to last point */ /* interpolate within 3rd to last point */ for (; dsp_phase_index <= end_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index - 3] + coeffs[1] * (float)dsp_data[dsp_phase_index - 2] + coeffs[2] * (float)dsp_data[dsp_phase_index - 1] + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)dsp_data[dsp_phase_index + 1] + coeffs[5] * (float)dsp_data[dsp_phase_index + 2] + coeffs[6] * (float)end_points0); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } end_index++; /* we're now interpolating the 2nd to last point */ /* interpolate within 2nd to last point */ for (; dsp_phase_index <= end_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index - 3] + coeffs[1] * (float)dsp_data[dsp_phase_index - 2] + coeffs[2] * (float)dsp_data[dsp_phase_index - 1] + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)dsp_data[dsp_phase_index + 1] + coeffs[5] * (float)end_points0 + coeffs[6] * (float)end_points1); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } end_index++; /* we're now interpolating the last point */ /* interpolate within last point */ for (; dsp_phase_index <= end_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = sinc_table7[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * (float)dsp_data[dsp_phase_index - 3] + coeffs[1] * (float)dsp_data[dsp_phase_index - 2] + coeffs[2] * (float)dsp_data[dsp_phase_index - 1] + coeffs[3] * (float)dsp_data[dsp_phase_index] + coeffs[4] * (float)end_points0 + coeffs[5] * (float)end_points1 + coeffs[6] * (float)end_points2); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } if (!looping) { break; /* break out if not looping (end of sample) */ } /* go back to loop start */ if (dsp_phase_index > end_index) { //fluid_phase_sub_int(dsp_phase, voice.loopend - voice.loopstart); dsp_phase -= ((ulong)(voice.loopend - voice.loopstart)) << 32; if (!voice.has_looped) { //Debug.LogFormat("has_looped end_index:{0} ", end_index); voice.has_looped = true; start_index = (uint)voice.loopstart; start_points0 = dsp_data[voice.loopend - 1]; start_points1 = dsp_data[voice.loopend - 2]; start_points2 = dsp_data[voice.loopend - 3]; } } /* break out if filled buffer */ if (dsp_i >= fluid_bufsize) { break; } end_index -= 3; /* set end back to 4th to last sample point */ } /* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on * the 4th sample point (correct back to real value) * Subtract b from a (both are fluid_phase_t). * #define fluid_phase_decr(a, b) a -= b * fluid_phase_decr(dsp_phase, (ulong)0x80000000); */ dsp_phase -= 0x80000000; voice.phase = dsp_phase; voice.amp = dsp_amp; return((int)dsp_i); }
/* 4th order (cubic) interpolation. * Returns number of samples processed (usually fluid_bufsize but could be * smaller if end of sample occurs). */ public static int fluid_dsp_float_interpolate_4th_order(fluid_voice voice) { ulong dsp_phase = voice.phase; ulong dsp_phase_incr;//, end_phase; float[] dsp_data = voice.sample.Data; float[] dsp_buf = voice.dsp_buf; float dsp_amp = voice.amp; float dsp_amp_incr = voice.amp_incr; uint dsp_i = 0; uint dsp_phase_index; uint start_index, end_index; float start_point, end_point1, end_point2; float[] coeffs; bool looping; int fluid_bufsize = voice.synth.FLUID_BUFSIZE; /* Convert playback "speed" floating point value to phase index/fract */ //fluid_phase_set_float(dsp_phase_incr, voice.phase_incr); dsp_phase_incr = (((ulong)voice.phase_incr) << 32) | (uint)(((double)(voice.phase_incr) - (int)(voice.phase_incr)) * (double)FLUID_FRACT_MAX); /* voice is currently looping? */ looping = ((voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_DURING_RELEASE) || (voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_UNTIL_RELEASE && voice.volenv_section < fluid_voice_envelope_index.FLUID_VOICE_ENVRELEASE)); //Debug.LogFormat("looping:{0} ", looping); /* last index before 4th interpolation point must be specially handled */ end_index = (uint)(looping ? voice.loopend - 1 : voice.end) - 2; if (voice.has_looped) /* set start_index and start point if looped or not */ { start_index = (uint)voice.loopstart; start_point = dsp_data[voice.loopend - 1]; /* last point in loop (wrap around) */ } else { start_index = (uint)voice.start; start_point = dsp_data[voice.start]; /* just duplicate the point */ } /* get points off the end (loop start if looping, duplicate point if end) */ if (looping) { end_point1 = dsp_data[voice.loopstart]; end_point2 = dsp_data[voice.loopstart + 1]; } else { end_point1 = dsp_data[voice.end]; end_point2 = end_point1; } while (true) { //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); /* interpolate first sample point (start or loop start) if needed */ for (; dsp_phase_index == start_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = (((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT; coeffs = interp_coeff[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * start_point + coeffs[1] * dsp_data[dsp_phase_index] + coeffs[2] * dsp_data[dsp_phase_index + 1] + coeffs[3] * dsp_data[dsp_phase_index + 2]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } /* interpolate the sequence of sample points */ for (; dsp_i < fluid_bufsize && dsp_phase_index <= end_index; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = interp_coeff[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index - 1] + coeffs[1] * dsp_data[dsp_phase_index] + coeffs[2] * dsp_data[dsp_phase_index + 1] + coeffs[3] * dsp_data[dsp_phase_index + 2]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } /* break out if buffer filled */ if (dsp_i >= fluid_bufsize) { break; } end_index++; /* we're now interpolating the 2nd to last point */ /* interpolate within 2nd to last point */ for (; dsp_phase_index <= end_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = interp_coeff[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index - 1] + coeffs[1] * dsp_data[dsp_phase_index] + coeffs[2] * dsp_data[dsp_phase_index + 1] + coeffs[3] * end_point1); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } end_index++; /* we're now interpolating the last point */ /* interpolate within the last point */ for (; dsp_phase_index <= end_index && dsp_i < fluid_bufsize; dsp_i++) { uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = interp_coeff[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index - 1] + coeffs[1] * dsp_data[dsp_phase_index] + coeffs[2] * end_point1 + coeffs[3] * end_point2); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } if (!looping) { break; /* break out if not looping (end of sample) */ } /* go back to loop start */ if (dsp_phase_index > end_index) { //fluid_phase_sub_int(dsp_phase, voice.loopend - voice.loopstart); dsp_phase -= ((ulong)(voice.loopend - voice.loopstart)) << 32; if (!voice.has_looped) { //Debug.LogFormat("has_looped end_index:{0} ", end_index); voice.has_looped = true; start_index = (uint)voice.loopstart; start_point = dsp_data[voice.loopend - 1]; } } /* break out if filled buffer */ if (dsp_i >= fluid_bufsize) { break; } end_index -= 2; /* set end back to third to last sample point */ } voice.phase = dsp_phase; voice.amp = dsp_amp; return((int)dsp_i); }
// No interpolation. Just take the sample, which is closest to the playback pointer. // Questionable quality, but very efficient. public static int fluid_dsp_float_interpolate_none(fluid_voice voice) { ulong dsp_phase = voice.phase; ulong dsp_phase_incr; float[] dsp_data = voice.sample.Data; float[] dsp_buf = voice.dsp_buf; float dsp_amp = voice.amp; float dsp_amp_incr = voice.amp_incr; uint dsp_i = 0; uint dsp_phase_index; uint end_index; bool looping; int fluid_bufsize = voice.synth.FLUID_BUFSIZE; //Debug.Log("fluid_dsp_float_interpolate_none"); /* Convert playback "speed" floating point value to phase index/fract * Sets the phase a to a phase increment given in b. * For example, assume b is 0.9. After setting a to it, adding a to the playing pointer will advance it by 0.9 samples. #define fluid_phase_set_float(a, b) (a) = (((unsigned long long)(b)) << 32) | (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX) * fluid_phase_set_float (dsp_phase_incr, phase_incr); */ dsp_phase_incr = (((ulong)voice.phase_incr) << 32) | (uint)(((double)(voice.phase_incr) - (int)(voice.phase_incr)) * (double)FLUID_FRACT_MAX); /* voice is currently looping? * looping = _SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE || (_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE && volenv_section < FLUID_VOICE_ENVRELEASE); */ looping = ((voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_DURING_RELEASE) || (voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_UNTIL_RELEASE && voice.volenv_section < fluid_voice_envelope_index.FLUID_VOICE_ENVRELEASE)); end_index = looping ? (uint)voice.loopend - 1 : (uint)voice.end; //if (looping)Debug.LogFormat(" looping at end_index:{0} ", end_index); while (true) { /* * Get the phase index with fractional rounding #define fluid_phase_index_round(_x) ((uint)(((_x) + 0x80000000) >> 32)) * dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */ dsp_phase_index = ((uint)((dsp_phase + 0x80000000) >> 32)); //Debug.LogFormat(" fluid_dsp_float_interpolate_none dsp_i:{0} dsp_phase_index:{1} end_index:{2} loopend:{3} end:{4} synth.fluid_bufsize:{5} sample.Data.Length:{6}", // dsp_i, dsp_phase_index, end_index, loopend, end, synth.fluid_bufsize, sample.Data.Length); /* interpolate sequence of sample points */ for (; dsp_i < fluid_bufsize && dsp_phase_index <= end_index; dsp_i++) { //Debug.LogFormat("dsp_i:{0} phase_incr:{1,0:F7} dsp_phase_index:{2} amp:{3,0:F7} dsp_buf:{4,0:F7} phase:{5}",dsp_i, dsp_phase_incr, dsp_phase_index, dsp_amp, dsp_buf[dsp_i], dsp_phase); dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index]; // increment phase and amplitude // Advance a by a step of b (both are ulong). // #define fluid_phase_incr(a, b) a += b // fluid_phase_incr (dsp_phase, dsp_phase_incr); // dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */ dsp_phase_index = ((uint)((dsp_phase + 0x80000000) >> 32)); dsp_amp += dsp_amp_incr; } /* break out if not looping (buffer may not be full) */ if (!looping) { break; } /* go back to loop start */ if (dsp_phase_index > end_index) { // Purpose: // Subtract b samples from a. // #define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32) // fluid_phase_sub_int (dsp_phase, loopend - loopstart); dsp_phase -= ((ulong)(voice.loopend - voice.loopstart)) << 32; voice.has_looped = true; //Debug.LogFormat(" return to start:{0} end_index:{1} ", ((uint)((dsp_phase + 0x80000000) >> 32)), end_index); } /* break out if filled buffer */ if (dsp_i >= fluid_bufsize) { break; } } voice.phase = dsp_phase; voice.amp = dsp_amp; return((int)dsp_i); }
/* Straight line interpolation. * Returns number of samples processed (usually fluid_bufsize but could be * smaller if end of sample occurs). */ public static int fluid_dsp_float_interpolate_linear(fluid_voice voice) { ulong dsp_phase = voice.phase; ulong dsp_phase_incr; float[] dsp_data = voice.sample.Data; float[] dsp_buf = voice.dsp_buf; float dsp_amp = voice.amp; float dsp_amp_incr = voice.amp_incr; uint dsp_i = 0; uint dsp_phase_index; uint end_index; float point; float[] coeffs; bool looping; int fluid_bufsize = voice.synth.FLUID_BUFSIZE; //Debug.Log("fluid_dsp_float_interpolate_linear"); /* Convert playback "speed" floating point value to phase index/fract * fluid_phase_set_float (dsp_phase_incr, voice->phase_incr); */ dsp_phase_incr = (((ulong)voice.phase_incr) << 32) | (uint)(((double)(voice.phase_incr) - (int)(voice.phase_incr)) * (double)FLUID_FRACT_MAX); /* voice is currently looping? */ looping = ((voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_DURING_RELEASE) || (voice.gens[(int)fluid_gen_type.GEN_SAMPLEMODE].Val == (double)fluid_loop.FLUID_LOOP_UNTIL_RELEASE && voice.volenv_section < fluid_voice_envelope_index.FLUID_VOICE_ENVRELEASE)); //Debug.LogFormat("looping:{0} ", looping); /* last index before 2nd interpolation point must be specially handled */ end_index = (looping ? (uint)voice.loopend - 1 : (uint)voice.end) - 1; /* 2nd interpolation point to use at end of loop or sample */ point = looping ? dsp_data[voice.loopstart] : dsp_data[voice.end]; /* duplicate end for samples no longer looping */ while (true) { /* Purpose: Return the index and the fractional part, respectively. #define fluid_phase_index(_x) ((unsigned int)((_x) >> 32)) * dsp_phase_index = fluid_phase_index(dsp_phase); */ dsp_phase_index = ((uint)((dsp_phase) >> 32)); /* interpolate the sequence of sample points */ for (; dsp_i < fluid_bufsize && dsp_phase_index <= end_index; dsp_i++) { /*Purpose: * Takes the fractional part of the argument phase and * calculates the corresponding position in the interpolation table. * The fractional position of the playing pointer is calculated with a quite high * resolution(32 bits). It would be unpractical to keep a set of interpolation * coefficients for each possible fractional part... #define fluid_phase_fract(_x) ((uint32)((_x) & 0xFFFFFFFF)) #define fluid_phase_fract_to_tablerow(_x) ((unsigned int) (fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT) * fluid_phase_fract_to_tablerow(dsp_phase) */ uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = interp_coeff_linear[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index] + coeffs[1] * dsp_data[dsp_phase_index + 1]); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; } /* break out if buffer filled */ if (dsp_i >= fluid_bufsize) { break; } end_index++; /* we're now interpolating the last point */ /* interpolate within last point */ for (; dsp_phase_index <= end_index && dsp_i < fluid_bufsize; dsp_i++) { /*Purpose: * Takes the fractional part of the argument phase and * calculates the corresponding position in the interpolation table. * The fractional position of the playing pointer is calculated with a quite high * resolution(32 bits). It would be unpractical to keep a set of interpolation * coefficients for each possible fractional part... #define fluid_phase_fract(_x) ((uint32)((_x) & 0xFFFFFFFF)) #define fluid_phase_fract_to_tablerow(_x) ((unsigned int) (fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT) */ //coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; uint tablerow = ((uint)(((uint)((dsp_phase) & 0xFFFFFFFF)) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT); coeffs = interp_coeff_linear[tablerow]; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index] + coeffs[1] * point); /* increment phase and amplitude */ //fluid_phase_incr(dsp_phase, dsp_phase_incr); dsp_phase += dsp_phase_incr; //dsp_phase_index = fluid_phase_index(dsp_phase); dsp_phase_index = ((uint)((dsp_phase) >> 32)); dsp_amp += dsp_amp_incr; /* increment amplitude */ } if (!looping) { break; /* break out if not looping (end of sample) */ } /* go back to loop start (if past */ if (dsp_phase_index > end_index) { /* Purpose: Subtract b samples from a. #define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32) * fluid_phase_sub_int(dsp_phase, voice.loopend - voice.loopstart); */ //Debug.LogFormat("has_looped end_index:{0} ", end_index); dsp_phase -= ((ulong)(voice.loopend - voice.loopstart)) << 32; voice.has_looped = true; } /* break out if filled buffer */ if (dsp_i >= fluid_bufsize) { break; } end_index--; /* set end back to second to last sample point */ } voice.phase = dsp_phase; voice.amp = dsp_amp; return((int)dsp_i); }
public ushort SfTrans; /* transform applied to source */ public double fluid_mod_get_value(fluid_channel chan, fluid_voice voice) { double v1 = 0.0, v2 = 1.0; double range1 = 127.0, range2 = 127.0; if (chan == null) { return(0.0f); } /* 'special treatment' for default controller * * Reference: SF2.01 section 8.4.2 * * The GM default controller 'vel-to-filter cut off' is not clearly defined: If implemented according to the specs, the filter * frequency jumps between vel=63 and vel=64. To maintain compatibility with existing sound fonts, the implementation is * 'hardcoded', it is impossible to implement using only one modulator otherwise. * * I assume here, that the 'intention' of the paragraph is one octave (1200 cents) filter frequency shift between vel=127 and * vel=64. 'amount' is (-2400), at least as long as the controller is set to default. * * Further, the 'appearance' of the modulator (source enumerator, destination enumerator, flags etc) is different from that * described in section 8.4.2, but it matches the definition used in several SF2.1 sound fonts (where it is used only to turn it off). * */ if ((Dest == (byte)fluid_gen_type.GEN_FILTERFC) && (Src2 == (int)fluid_mod_src.FLUID_MOD_VELOCITY) && (Src1 == (int)fluid_mod_src.FLUID_MOD_VELOCITY) && (Flags1 == ((byte)fluid_mod_flags.FLUID_MOD_GC | (byte)fluid_mod_flags.FLUID_MOD_UNIPOLAR | (byte)fluid_mod_flags.FLUID_MOD_NEGATIVE | (byte)fluid_mod_flags.FLUID_MOD_LINEAR)) && (Flags2 == ((byte)fluid_mod_flags.FLUID_MOD_GC | (byte)fluid_mod_flags.FLUID_MOD_UNIPOLAR | (byte)fluid_mod_flags.FLUID_MOD_POSITIVE | (byte)fluid_mod_flags.FLUID_MOD_SWITCH))) { if (voice.vel < 64) { return((double)Amount / 2.0); } else { return((double)Amount * (127 - voice.vel) / 127); } } /* get the initial value of the first source */ if (Src1 > 0) { if ((Flags1 & (byte)fluid_mod_flags.FLUID_MOD_CC) > 0) { v1 = ((Src1 >= 0) && (Src1 < 128)) ? chan.cc[Src1] : 0; //if (src1 == 10) Debug.Log("retreive pan " + v1); } else { /* source 1 is one of the direct controllers */ switch (Src1) { case (int)fluid_mod_src.FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */ v1 = range1; break; case (int)fluid_mod_src.FLUID_MOD_VELOCITY: v1 = voice.vel; break; case (int)fluid_mod_src.FLUID_MOD_KEY: v1 = voice.key; break; case (int)fluid_mod_src.FLUID_MOD_KEYPRESSURE: v1 = chan.key_pressure; break; case (int)fluid_mod_src.FLUID_MOD_CHANNELPRESSURE: v1 = chan.channel_pressure; break; case (int)fluid_mod_src.FLUID_MOD_PITCHWHEEL: v1 = chan.pitch_bend; range1 = 0x4000; break; case (int)fluid_mod_src.FLUID_MOD_PITCHWHEELSENS: v1 = chan.pitch_wheel_sensitivity; break; default: v1 = 0.0; break; } } /* transform the input value */ switch (Flags1 & 0x0f) { case 0: /* linear, unipolar, positive */ v1 /= range1; break; case 1: /* linear, unipolar, negative */ v1 = 1.0f - v1 / range1; break; case 2: /* linear, bipolar, positive */ v1 = -1.0f + 2.0f * v1 / range1; break; case 3: /* linear, bipolar, negative */ v1 = -1.0f + 2.0f * v1 / range1; break; case 4: /* concave, unipolar, positive */ v1 = fluid_conv.fluid_concave(v1); break; case 5: /* concave, unipolar, negative */ v1 = fluid_conv.fluid_concave(127 - v1); break; case 6: /* concave, bipolar, positive */ v1 = (v1 > 64) ? fluid_conv.fluid_concave(2 * (v1 - 64)) : -fluid_conv.fluid_concave(2 * (64 - v1)); break; case 7: /* concave, bipolar, negative */ v1 = (v1 > 64) ? -fluid_conv.fluid_concave(2 * (v1 - 64)) : fluid_conv.fluid_concave(2 * (64 - v1)); break; case 8: /* convex, unipolar, positive */ v1 = fluid_conv.fluid_convex(v1); break; case 9: /* convex, unipolar, negative */ v1 = fluid_conv.fluid_convex(127 - v1); break; case 10: /* convex, bipolar, positive */ v1 = (v1 > 64) ? -fluid_conv.fluid_convex(2 * (v1 - 64)) : fluid_conv.fluid_convex(2 * (64 - v1)); break; case 11: /* convex, bipolar, negative */ v1 = (v1 > 64) ? -fluid_conv.fluid_convex(2 * (v1 - 64)) : fluid_conv.fluid_convex(2 * (64 - v1)); break; case 12: /* switch, unipolar, positive */ v1 = (v1 >= 64) ? 1.0f : 0.0f; break; case 13: /* switch, unipolar, negative */ v1 = (v1 >= 64) ? 0.0f : 1.0f; break; case 14: /* switch, bipolar, positive */ v1 = (v1 >= 64) ? 1.0f : -1.0f; break; case 15: /* switch, bipolar, negative */ v1 = (v1 >= 64) ? -1.0f : 1.0f; break; } } else { return(0.0); } /* no need to go further */ if (v1 == 0.0f) { return(0.0f); } /* get the second input source */ if (Src2 > 0) { if ((Flags2 & (byte)fluid_mod_flags.FLUID_MOD_CC) > 0) { v2 = ((Src2 >= 0) && (Src2 < 128)) ? chan.cc[Src2] : 0; } else { switch (Src2) { case (int)fluid_mod_src.FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */ v2 = range2; break; case (int)fluid_mod_src.FLUID_MOD_VELOCITY: v2 = voice.vel; break; case (int)fluid_mod_src.FLUID_MOD_KEY: v2 = voice.key; break; case (int)fluid_mod_src.FLUID_MOD_KEYPRESSURE: v2 = chan.key_pressure; break; case (int)fluid_mod_src.FLUID_MOD_CHANNELPRESSURE: v2 = chan.channel_pressure; break; case (int)fluid_mod_src.FLUID_MOD_PITCHWHEEL: v2 = chan.pitch_bend; break; case (int)fluid_mod_src.FLUID_MOD_PITCHWHEELSENS: v2 = chan.pitch_wheel_sensitivity; break; default: v1 = 0.0f; break; } } /* transform the second input value */ switch (Flags2 & 0x0f) { case 0: /* linear, unipolar, positive */ v2 /= range2; break; case 1: /* linear, unipolar, negative */ v2 = 1.0f - v2 / range2; break; case 2: /* linear, bipolar, positive */ v2 = -1.0f + 2.0f * v2 / range2; break; case 3: /* linear, bipolar, negative */ v2 = -1.0f + 2.0f * v2 / range2; break; case 4: /* concave, unipolar, positive */ v2 = fluid_conv.fluid_concave(v2); break; case 5: /* concave, unipolar, negative */ v2 = fluid_conv.fluid_concave(127 - v2); break; case 6: /* concave, bipolar, positive */ v2 = (v2 > 64) ? fluid_conv.fluid_concave(2 * (v2 - 64)) : -fluid_conv.fluid_concave(2 * (64 - v2)); break; case 7: /* concave, bipolar, negative */ v2 = (v2 > 64) ? -fluid_conv.fluid_concave(2 * (v2 - 64)) : fluid_conv.fluid_concave(2 * (64 - v2)); break; case 8: /* convex, unipolar, positive */ v2 = fluid_conv.fluid_convex(v2); break; case 9: /* convex, unipolar, negative */ v2 = 1.0f - fluid_conv.fluid_convex(v2); break; case 10: /* convex, bipolar, positive */ v2 = (v2 > 64) ? -fluid_conv.fluid_convex(2 * (v2 - 64)) : fluid_conv.fluid_convex(2 * (64 - v2)); break; case 11: /* convex, bipolar, negative */ v2 = (v2 > 64) ? -fluid_conv.fluid_convex(2 * (v2 - 64)) : fluid_conv.fluid_convex(2 * (64 - v2)); break; case 12: /* switch, unipolar, positive */ v2 = (v2 >= 64) ? 1.0f : 0.0f; break; case 13: /* switch, unipolar, negative */ v2 = (v2 >= 64) ? 0.0f : 1.0f; break; case 14: /* switch, bipolar, positive */ v2 = (v2 >= 64) ? 1.0f : -1.0f; break; case 15: /* switch, bipolar, negative */ v2 = (v2 >= 64) ? -1.0f : 1.0f; break; } } else { v2 = 1.0f; } /* it's as simple as that: */ return((double)Amount * v1 * v2); }