public virtual void generateTones(ChannelUnitContext ctx, int chNum, int sb, float[] @out, int outOffset) { float[] wavreg1 = new float[128]; float[] wavreg2 = new float[128]; WavesData tonesNow = ctx.channels[chNum].tonesInfoPrev[sb]; WavesData tonesNext = ctx.channels[chNum].tonesInfo[sb]; // reconstruct full envelopes for both overlapping regions // from truncated bitstream data if (tonesNext.pendEnv.hasStartPoint && tonesNext.pendEnv.startPos < tonesNext.pendEnv.stopPos) { tonesNext.currEnv.hasStartPoint = true; tonesNext.currEnv.startPos = tonesNext.pendEnv.startPos + 32; } else if (tonesNow.pendEnv.hasStartPoint) { tonesNext.currEnv.hasStartPoint = true; tonesNext.currEnv.startPos = tonesNow.pendEnv.startPos; } else { tonesNext.currEnv.hasStartPoint = false; tonesNext.currEnv.startPos = 0; } if (tonesNow.pendEnv.hasStopPoint && tonesNow.pendEnv.stopPos >= tonesNext.currEnv.startPos) { tonesNext.currEnv.hasStopPoint = true; tonesNext.currEnv.stopPos = tonesNow.pendEnv.stopPos; } else if (tonesNext.pendEnv.hasStopPoint) { tonesNext.currEnv.hasStopPoint = true; tonesNext.currEnv.stopPos = tonesNext.pendEnv.stopPos + 32; } else { tonesNext.currEnv.hasStopPoint = false; tonesNext.currEnv.stopPos = 64; } // is the visible part of the envelope non-zero? bool reg1EnvNonzero = (tonesNow.currEnv.stopPos < 32 ? false : true); bool reg2EnvNonzero = (tonesNext.currEnv.startPos >= 32 ? false : true); // synthesize waves for both overlapping regions if (tonesNow.numWavs > 0 && reg1EnvNonzero) { wavesSynth(ctx.wavesInfoPrev, tonesNow, tonesNow.currEnv, ctx.wavesInfoPrev.phaseShift[sb] && (chNum > 0), 128, wavreg1); } if (tonesNext.numWavs > 0 && reg2EnvNonzero) { wavesSynth(ctx.wavesInfo, tonesNext, tonesNext.currEnv, ctx.wavesInfo.phaseShift[sb] && (chNum > 0), 0, wavreg2); } // Hann windowing for non-faded wave signals if (tonesNow.numWavs > 0 && tonesNext.numWavs > 0 && reg1EnvNonzero && reg2EnvNonzero) { vectorFmul(wavreg1, 0, wavreg1, 0, hann_window, 128, 128); vectorFmul(wavreg2, 0, wavreg2, 0, hann_window, 0, 128); } else { if (tonesNow.numWavs > 0 && !tonesNow.currEnv.hasStopPoint) { vectorFmul(wavreg1, 0, wavreg1, 0, hann_window, 128, 128); } if (tonesNext.numWavs > 0 && !tonesNext.currEnv.hasStartPoint) { vectorFmul(wavreg2, 0, wavreg2, 0, hann_window, 0, 128); } } // Overlap and add to residual for (int i = 0; i < 128; i++) { @out[outOffset + i] += wavreg1[i] + wavreg2[i]; } }
/// <summary> /// Synthesize sine waves according to given parameters. /// /// @param[in] synthParam common synthesis parameters /// @param[in] wavesInfo parameters for each sine wave /// @param[in] envelope envelope data for all waves in a group /// @param[in] phaseShift flag indicates 180 degrees phase shift /// @param[in] regOffset region offset for trimming envelope data /// @param[out] out receives synthesized data /// </summary> private void wavesSynth(WaveSynthParams synthParams, WavesData wavesInfo, WaveEnvelope envelope, bool phaseShift, int regOffset, float[] @out) { int waveParam = wavesInfo.startIndex; for (int wn = 0; wn < wavesInfo.numWavs; wn++, waveParam++) { // amplitude dequantization double amp = amp_sf_tab[synthParams.waves[waveParam].ampSf] * (synthParams.amplitudeMode == 0 ? (synthParams.waves[waveParam].ampIndex + 1) / 15.13f : 1.0f); int inc = synthParams.waves[waveParam].freqIndex; int pos = DEQUANT_PHASE(synthParams.waves[waveParam].phaseIndex) - (regOffset ^ 128) * inc & 2047; // waveform generation for (int i = 0; i < 128; i++) { @out[i] += (float)(sine_table[pos] * amp); pos = (pos + inc) & 2047; } } if (phaseShift) { // 180 degrees phase shift for (int i = 0; i < 128; i++) { //JAVA TO C# CONVERTER TODO TASK: The following line could not be converted: @out[i] = -@out[i]; } } // fade in with steep Hann window if requested if (envelope.hasStartPoint) { int pos = (envelope.startPos << 2) - regOffset; if (pos > 0 && pos <= 128) { Arrays.Fill(@out, 0, pos, 0f); if (!envelope.hasStopPoint || envelope.startPos != envelope.stopPos) { @out[pos + 0] *= hann_window[0]; @out[pos + 1] *= hann_window[32]; @out[pos + 2] *= hann_window[64]; @out[pos + 3] *= hann_window[96]; } } } // fade out with steep Hann window if requested if (envelope.hasStopPoint) { int pos = (envelope.stopPos + 1 << 2) - regOffset; if (pos > 0 && pos <= 128) { @out[pos - 4] *= hann_window[96]; @out[pos - 3] *= hann_window[64]; @out[pos - 2] *= hann_window[32]; @out[pos - 1] *= hann_window[0]; Arrays.Fill(@out, pos, 128, 0f); } } }