namespace NSpeex
|
{
|
using System;
|
|
internal class SbEncoder : SbCodec, IEncoder
|
{
|
protected internal float abr_count;
|
protected internal float abr_drift;
|
protected internal float abr_drift2;
|
protected internal int abr_enabled;
|
private float[] autocorr;
|
private float[] buf;
|
private float[] bw_lpc1;
|
private float[] bw_lpc2;
|
protected internal int complexity;
|
private float[] h0_mem;
|
private float[] interp_lpc;
|
private float[] interp_lsp;
|
private float[] lagWindow;
|
protected internal IEncoder lowenc;
|
private float[] lsp;
|
private float[] mem_sp2;
|
private float[] mem_sw;
|
protected internal int nb_modes;
|
private static readonly int[] NB_QUALITY_MAP = new int[] { 1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7 };
|
private float[] old_lsp;
|
private float[] rc;
|
protected internal float relative_quality;
|
private float[] res;
|
protected internal int sampling_rate;
|
protected internal int submodeSelect;
|
private float[] swBuf;
|
private float[] target;
|
private bool uwb;
|
private static readonly int[] UWB_QUALITY_MAP = new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
protected internal int vad_enabled;
|
protected internal int vbr_enabled;
|
protected internal float vbr_quality;
|
private static readonly int[] WB_QUALITY_MAP = new int[] { 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4 };
|
private float[] window;
|
private float[] x1d;
|
|
public SbEncoder(bool ultraWide) : base(ultraWide)
|
{
|
if (ultraWide)
|
{
|
this.Uwbinit();
|
}
|
else
|
{
|
this.Wbinit();
|
}
|
}
|
|
public virtual int Encode(Bits bits, float[] ins0)
|
{
|
int num;
|
int num2;
|
Filters.Qmf_decomp(ins0, Codebook_Constants.h0, base.x0d, this.x1d, base.fullFrameSize, 0x40, this.h0_mem);
|
this.lowenc.Encode(bits, base.x0d);
|
for (num = 0; num < (base.windowSize - base.frameSize); num++)
|
{
|
base.high[num] = base.high[base.frameSize + num];
|
}
|
for (num = 0; num < base.frameSize; num++)
|
{
|
base.high[(base.windowSize - base.frameSize) + num] = this.x1d[num];
|
}
|
Array.Copy(base.excBuf, base.frameSize, base.excBuf, 0, base.bufSize - base.frameSize);
|
float[] piGain = this.lowenc.PiGain;
|
float[] exc = this.lowenc.Exc;
|
float[] innov = this.lowenc.Innov;
|
if (this.lowenc.Mode == 0)
|
{
|
num2 = 1;
|
}
|
else
|
{
|
num2 = 0;
|
}
|
num = 0;
|
while (num < base.windowSize)
|
{
|
this.buf[num] = base.high[num] * this.window[num];
|
num++;
|
}
|
Lpc.Autocorr(this.buf, this.autocorr, base.lpcSize + 1, base.windowSize);
|
this.autocorr[0]++;
|
this.autocorr[0] *= base.lpc_floor;
|
for (num = 0; num < (base.lpcSize + 1); num++)
|
{
|
this.autocorr[num] *= this.lagWindow[num];
|
}
|
Lpc.Wld(base.lpc, this.autocorr, this.rc, base.lpcSize);
|
Array.Copy(base.lpc, 0, base.lpc, 1, base.lpcSize);
|
base.lpc[0] = 1f;
|
if ((Lsp.Lpc2lsp(base.lpc, base.lpcSize, this.lsp, 15, 0.2f) != base.lpcSize) && (Lsp.Lpc2lsp(base.lpc, base.lpcSize, this.lsp, 11, 0.02f) != base.lpcSize))
|
{
|
for (num = 0; num < base.lpcSize; num++)
|
{
|
this.lsp[num] = (float)Math.Cos((3.1415926535897931 * (num + 1)) / ((double)(base.lpcSize + 1)));
|
}
|
}
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
this.lsp[num] = (float)Math.Acos((double)this.lsp[num]);
|
num++;
|
}
|
float num5 = 0f;
|
for (num = 0; num < base.lpcSize; num++)
|
{
|
num5 += (this.old_lsp[num] - this.lsp[num]) * (this.old_lsp[num] - this.lsp[num]);
|
}
|
if (((this.vbr_enabled != 0) || (this.vad_enabled != 0)) && (num2 == 0))
|
{
|
float num6 = 0f;
|
float num7 = 0f;
|
if (this.abr_enabled != 0)
|
{
|
float num9 = 0f;
|
if ((this.abr_drift2 * this.abr_drift) > 0f)
|
{
|
num9 = (-1E-05f * this.abr_drift) / (1f + this.abr_count);
|
if (num9 > 0.1f)
|
{
|
num9 = 0.1f;
|
}
|
if (num9 < -0.1f)
|
{
|
num9 = -0.1f;
|
}
|
}
|
this.vbr_quality += num9;
|
if (this.vbr_quality > 10f)
|
{
|
this.vbr_quality = 10f;
|
}
|
if (this.vbr_quality < 0f)
|
{
|
this.vbr_quality = 0f;
|
}
|
}
|
num = 0;
|
while (num < base.frameSize)
|
{
|
num6 += base.x0d[num] * base.x0d[num];
|
num7 += base.high[num] * base.high[num];
|
num++;
|
}
|
float num8 = (float)Math.Log((double)((1f + num7) / (1f + num6)));
|
this.relative_quality = this.lowenc.RelativeQuality;
|
if (num8 < -4f)
|
{
|
num8 = -4f;
|
}
|
if (num8 > 2f)
|
{
|
num8 = 2f;
|
}
|
if (this.vbr_enabled == 0)
|
{
|
int submodeSelect;
|
if (this.relative_quality < 2.0)
|
{
|
submodeSelect = 1;
|
}
|
else
|
{
|
submodeSelect = this.submodeSelect;
|
}
|
base.submodeID = submodeSelect;
|
}
|
else
|
{
|
int index = this.nb_modes - 1;
|
this.relative_quality += 1f * (num8 + 2f);
|
if (this.relative_quality < -1f)
|
{
|
this.relative_quality = -1f;
|
}
|
while (index != 0)
|
{
|
float num12;
|
int num11 = (int)Math.Floor((double)this.vbr_quality);
|
if (num11 == 10)
|
{
|
num12 = NSpeex.Vbr.hb_thresh[index][num11];
|
}
|
else
|
{
|
num12 = ((this.vbr_quality - num11) * NSpeex.Vbr.hb_thresh[index][num11 + 1]) + (((1 + num11) - this.vbr_quality) * NSpeex.Vbr.hb_thresh[index][num11]);
|
}
|
if (this.relative_quality >= num12)
|
{
|
break;
|
}
|
index--;
|
}
|
this.Mode = index;
|
if (this.abr_enabled != 0)
|
{
|
int bitRate = this.BitRate;
|
this.abr_drift += bitRate - this.abr_enabled;
|
this.abr_drift2 = (0.95f * this.abr_drift2) + (0.05f * (bitRate - this.abr_enabled));
|
this.abr_count++;
|
}
|
}
|
}
|
bits.Pack(1, 1);
|
if (num2 != 0)
|
{
|
bits.Pack(0, 3);
|
}
|
else
|
{
|
bits.Pack(base.submodeID, 3);
|
}
|
if ((num2 != 0) || (base.submodes[base.submodeID] == null))
|
{
|
for (num = 0; num < base.frameSize; num++)
|
{
|
base.excBuf[base.excIdx + num] = this.swBuf[num] = 0f;
|
}
|
for (num = 0; num < base.lpcSize; num++)
|
{
|
this.mem_sw[num] = 0f;
|
}
|
base.first = 1;
|
Filters.Iir_mem2(base.excBuf, base.excIdx, base.interp_qlpc, base.high, 0, base.subframeSize, base.lpcSize, base.mem_sp);
|
base.filters.Fir_mem_up(base.x0d, Codebook_Constants.h0, base.y0, base.fullFrameSize, 0x40, base.g0_mem);
|
base.filters.Fir_mem_up(base.high, Codebook_Constants.h1, base.y1, base.fullFrameSize, 0x40, base.g1_mem);
|
for (num = 0; num < base.fullFrameSize; num++)
|
{
|
ins0[num] = 2f * (base.y0[num] - base.y1[num]);
|
}
|
if (num2 != 0)
|
{
|
return 0;
|
}
|
return 1;
|
}
|
base.submodes[base.submodeID].LsqQuant.Quant(this.lsp, base.qlsp, base.lpcSize, bits);
|
if (base.first != 0)
|
{
|
for (num = 0; num < base.lpcSize; num++)
|
{
|
this.old_lsp[num] = this.lsp[num];
|
}
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
base.old_qlsp[num] = base.qlsp[num];
|
num++;
|
}
|
}
|
float[] mem = new float[base.lpcSize];
|
float[] y = new float[base.subframeSize];
|
float[] numArray2 = new float[base.subframeSize];
|
for (int i = 0; i < base.nbSubframes; i++)
|
{
|
float num24;
|
float num25 = 0f;
|
float num26 = 0f;
|
int num22 = base.subframeSize * i;
|
int xs = num22;
|
int ys = base.excIdx + num22;
|
int num21 = num22;
|
int num20 = num22;
|
float num16 = (1f + i) / ((float)base.nbSubframes);
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
this.interp_lsp[num] = ((1f - num16) * this.old_lsp[num]) + (num16 * this.lsp[num]);
|
num++;
|
}
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
base.interp_qlsp[num] = ((1f - num16) * base.old_qlsp[num]) + (num16 * base.qlsp[num]);
|
num++;
|
}
|
Lsp.Enforce_margin(this.interp_lsp, base.lpcSize, 0.05f);
|
Lsp.Enforce_margin(base.interp_qlsp, base.lpcSize, 0.05f);
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
this.interp_lsp[num] = (float)Math.Cos((double)this.interp_lsp[num]);
|
num++;
|
}
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
base.interp_qlsp[num] = (float)Math.Cos((double)base.interp_qlsp[num]);
|
num++;
|
}
|
base.m_lsp.Lsp2lpc(this.interp_lsp, this.interp_lpc, base.lpcSize);
|
base.m_lsp.Lsp2lpc(base.interp_qlsp, base.interp_qlpc, base.lpcSize);
|
Filters.Bw_lpc(base.gamma1, this.interp_lpc, this.bw_lpc1, base.lpcSize);
|
Filters.Bw_lpc(base.gamma2, this.interp_lpc, this.bw_lpc2, base.lpcSize);
|
float num23 = num24 = 0f;
|
num16 = 1f;
|
base.pi_gain[i] = 0f;
|
num = 0;
|
while (num <= base.lpcSize)
|
{
|
num24 += num16 * base.interp_qlpc[num];
|
num16 = -num16;
|
base.pi_gain[i] += base.interp_qlpc[num];
|
num++;
|
}
|
num23 = piGain[i];
|
num23 = 1f / (Math.Abs(num23) + 0.01f);
|
num24 = 1f / (Math.Abs(num24) + 0.01f);
|
float num17 = Math.Abs((float)(0.01f + num24)) / (0.01f + Math.Abs(num23));
|
Filters.Fir_mem2(base.high, xs, base.interp_qlpc, base.excBuf, ys, base.subframeSize, base.lpcSize, this.mem_sp2);
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
num25 += base.excBuf[ys + num] * base.excBuf[ys + num];
|
num++;
|
}
|
if (base.submodes[base.submodeID].Innovation == null)
|
{
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
num26 += innov[num22 + num] * innov[num22 + num];
|
num++;
|
}
|
float num27 = num25 / (0.01f + num26);
|
num27 = (float)Math.Sqrt((double)num27);
|
num27 *= num17;
|
int data = (int)Math.Floor((double)(10.5 + (8.0 * Math.Log(num27 + 0.0001))));
|
if (data < 0)
|
{
|
data = 0;
|
}
|
if (data > 0x1f)
|
{
|
data = 0x1f;
|
}
|
bits.Pack(data, 5);
|
num27 = (float)(0.1 * Math.Exp(((double)data) / 9.4));
|
num27 /= num17;
|
}
|
else
|
{
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
num26 += exc[num22 + num] * exc[num22 + num];
|
num++;
|
}
|
float num29 = (float)((Math.Sqrt((double)(1f + num25)) * num17) / Math.Sqrt((double)((1f + num26) * base.subframeSize)));
|
int num32 = (int)Math.Floor((double)(0.5 + (3.7 * (Math.Log((double)num29) + 2.0))));
|
if (num32 < 0)
|
{
|
num32 = 0;
|
}
|
if (num32 > 15)
|
{
|
num32 = 15;
|
}
|
bits.Pack(num32, 4);
|
num29 = (float)Math.Exp((0.27027027027027023 * num32) - 2.0);
|
float num30 = (num29 * ((float)Math.Sqrt((double)(1f + num26)))) / num17;
|
float num31 = 1f / num30;
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
base.excBuf[ys + num] = 0f;
|
num++;
|
}
|
base.excBuf[ys] = 1f;
|
Filters.Syn_percep_zero(base.excBuf, ys, base.interp_qlpc, this.bw_lpc1, this.bw_lpc2, y, base.subframeSize, base.lpcSize);
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
base.excBuf[ys + num] = 0f;
|
num++;
|
}
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
mem[num] = base.mem_sp[num];
|
num++;
|
}
|
Filters.Iir_mem2(base.excBuf, ys, base.interp_qlpc, base.excBuf, ys, base.subframeSize, base.lpcSize, mem);
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
mem[num] = this.mem_sw[num];
|
num++;
|
}
|
Filters.Filter_mem2(base.excBuf, ys, this.bw_lpc1, this.bw_lpc2, this.res, num21, base.subframeSize, base.lpcSize, mem, 0);
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
mem[num] = this.mem_sw[num];
|
num++;
|
}
|
Filters.Filter_mem2(base.high, xs, this.bw_lpc1, this.bw_lpc2, this.swBuf, num20, base.subframeSize, base.lpcSize, mem, 0);
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
this.target[num] = this.swBuf[num20 + num] - this.res[num21 + num];
|
num++;
|
}
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
base.excBuf[ys + num] = 0f;
|
num++;
|
}
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
this.target[num] *= num31;
|
num++;
|
}
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
numArray2[num] = 0f;
|
num++;
|
}
|
base.submodes[base.submodeID].Innovation.Quantify(this.target, base.interp_qlpc, this.bw_lpc1, this.bw_lpc2, base.lpcSize, base.subframeSize, numArray2, 0, y, bits, (this.complexity + 1) >> 1);
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
base.excBuf[ys + num] += numArray2[num] * num30;
|
num++;
|
}
|
if (base.submodes[base.submodeID].DoubleCodebook != 0)
|
{
|
float[] numArray7 = new float[base.subframeSize];
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
numArray7[num] = 0f;
|
num++;
|
}
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
this.target[num] *= 2.5f;
|
num++;
|
}
|
base.submodes[base.submodeID].Innovation.Quantify(this.target, base.interp_qlpc, this.bw_lpc1, this.bw_lpc2, base.lpcSize, base.subframeSize, numArray7, 0, y, bits, (this.complexity + 1) >> 1);
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
numArray7[num] *= (float)(num30 * 0.4);
|
num++;
|
}
|
num = 0;
|
while (num < base.subframeSize)
|
{
|
base.excBuf[ys + num] += numArray7[num];
|
num++;
|
}
|
}
|
}
|
num = 0;
|
while (num < base.lpcSize)
|
{
|
mem[num] = base.mem_sp[num];
|
num++;
|
}
|
Filters.Iir_mem2(base.excBuf, ys, base.interp_qlpc, base.high, xs, base.subframeSize, base.lpcSize, base.mem_sp);
|
Filters.Filter_mem2(base.high, xs, this.bw_lpc1, this.bw_lpc2, this.swBuf, num20, base.subframeSize, base.lpcSize, this.mem_sw, 0);
|
}
|
base.filters.Fir_mem_up(base.x0d, Codebook_Constants.h0, base.y0, base.fullFrameSize, 0x40, base.g0_mem);
|
base.filters.Fir_mem_up(base.high, Codebook_Constants.h1, base.y1, base.fullFrameSize, 0x40, base.g1_mem);
|
for (num = 0; num < base.fullFrameSize; num++)
|
{
|
ins0[num] = 2f * (base.y0[num] - base.y1[num]);
|
}
|
for (num = 0; num < base.lpcSize; num++)
|
{
|
this.old_lsp[num] = this.lsp[num];
|
}
|
for (num = 0; num < base.lpcSize; num++)
|
{
|
base.old_qlsp[num] = base.qlsp[num];
|
}
|
base.first = 0;
|
return 1;
|
}
|
|
protected override void Init(int frameSize, int subframeSize, int lpcSize, int bufSize, float foldingGain)
|
{
|
base.Init(frameSize, subframeSize, lpcSize, bufSize, foldingGain);
|
this.complexity = 3;
|
this.vbr_enabled = 0;
|
this.vad_enabled = 0;
|
this.abr_enabled = 0;
|
this.vbr_quality = 8f;
|
this.submodeSelect = base.submodeID;
|
this.x1d = new float[frameSize];
|
this.h0_mem = new float[0x40];
|
this.buf = new float[base.windowSize];
|
this.swBuf = new float[frameSize];
|
this.res = new float[frameSize];
|
this.target = new float[subframeSize];
|
this.window = Misc.Window(base.windowSize, subframeSize);
|
this.lagWindow = Misc.LagWindow(lpcSize, base.lag_factor);
|
this.rc = new float[lpcSize];
|
this.autocorr = new float[lpcSize + 1];
|
this.lsp = new float[lpcSize];
|
this.old_lsp = new float[lpcSize];
|
this.interp_lsp = new float[lpcSize];
|
this.interp_lpc = new float[lpcSize + 1];
|
this.bw_lpc1 = new float[lpcSize + 1];
|
this.bw_lpc2 = new float[lpcSize + 1];
|
this.mem_sp2 = new float[lpcSize];
|
this.mem_sw = new float[lpcSize];
|
this.abr_count = 0f;
|
}
|
|
private void Uwbinit()
|
{
|
this.lowenc = new SbEncoder(false);
|
this.Init(320, 80, 8, 0x500, 0.7f);
|
this.uwb = true;
|
this.nb_modes = 2;
|
this.sampling_rate = 0x7d00;
|
}
|
|
private void Wbinit()
|
{
|
this.lowenc = new NbEncoder();
|
this.Init(160, 40, 8, 640, 0.9f);
|
this.uwb = false;
|
this.nb_modes = 5;
|
this.sampling_rate = 0x3e80;
|
}
|
|
public virtual int Abr {
|
get { return this.abr_enabled; }
|
set {
|
this.lowenc.Vbr = true;
|
this.abr_enabled = (value != 0) ? 1 : 0;
|
this.vbr_enabled = 1;
|
int num = 10;
|
int num3 = value;
|
while (num >= 0)
|
{
|
this.Quality = num;
|
if (this.BitRate <= num3)
|
{
|
break;
|
}
|
num--;
|
}
|
float num4 = num;
|
if (num4 < 0f)
|
{
|
num4 = 0f;
|
}
|
this.VbrQuality = num4;
|
this.abr_count = 0f;
|
this.abr_drift = 0f;
|
this.abr_drift2 = 0f;
|
}
|
}
|
|
public virtual int BitRate {
|
get {
|
if (base.submodes[base.submodeID] != null)
|
{
|
return (this.lowenc.BitRate + ((this.sampling_rate * base.submodes[base.submodeID].BitsPerFrame) / base.frameSize));
|
}
|
return (this.lowenc.BitRate + ((this.sampling_rate * 4) / base.frameSize));
|
}
|
set {
|
for (int i = 10; i >= 0; i--)
|
{
|
this.Quality = i;
|
if (this.BitRate <= value)
|
{
|
return;
|
}
|
}
|
}
|
}
|
|
public virtual int Complexity {
|
get { return this.complexity; }
|
set {
|
if (value < 0)
|
{
|
value = 0;
|
}
|
if (value > 10)
|
{
|
value = 10;
|
}
|
this.complexity = value;
|
}
|
}
|
|
public bool Dtx {
|
get { return (base.dtx_enabled == 1); }
|
set {
|
base.dtx_enabled = value ? 1 : 0;
|
}
|
}
|
|
public virtual int EncodedFrameSize {
|
get {
|
int num = SbCodec.SB_FRAME_SIZE[base.submodeID];
|
return (num + this.lowenc.EncodedFrameSize);
|
}
|
}
|
|
public virtual int LookAhead { get { return (((2 * this.lowenc.LookAhead) + 0x40) - 1); } }
|
|
public virtual int Mode {
|
get { return base.submodeID; }
|
set {
|
if (value < 0)
|
{
|
value = 0;
|
}
|
base.submodeID = this.submodeSelect = value;
|
}
|
}
|
|
public virtual int Quality {
|
set {
|
if (value < 0)
|
{
|
value = 0;
|
}
|
if (value > 10)
|
{
|
value = 10;
|
}
|
if (this.uwb)
|
{
|
this.lowenc.Quality = value;
|
this.Mode = UWB_QUALITY_MAP[value];
|
}
|
else
|
{
|
this.lowenc.Mode = NB_QUALITY_MAP[value];
|
this.Mode = WB_QUALITY_MAP[value];
|
}
|
}
|
}
|
|
public virtual float RelativeQuality { get { return this.relative_quality; } }
|
|
public virtual int SamplingRate {
|
get { return this.sampling_rate; }
|
set {
|
this.sampling_rate = value;
|
this.lowenc.SamplingRate = value;
|
}
|
}
|
|
public virtual bool Vad {
|
get { return (this.vad_enabled != 0); }
|
set {
|
this.vad_enabled = value ? 1 : 0;
|
}
|
}
|
|
public virtual bool Vbr {
|
get { return (this.vbr_enabled != 0); }
|
set {
|
this.vbr_enabled = value ? 1 : 0;
|
this.lowenc.Vbr = value;
|
}
|
}
|
|
public virtual float VbrQuality {
|
get { return this.vbr_quality; }
|
set {
|
this.vbr_quality = value;
|
float num = value + 0.6f;
|
if (num > 10f)
|
{
|
num = 10f;
|
}
|
this.lowenc.VbrQuality = num;
|
int num2 = (int)Math.Floor((double)(0.5 + value));
|
if (num2 > 10)
|
{
|
num2 = 10;
|
}
|
this.Quality = num2;
|
}
|
}
|
}
|
}
|