Sanjay Govind 10 ay önce
ebeveyn
işleme
244f8ef4bf
4 değiştirilmiş dosya ile 727 ekleme ve 4 silme
  1. 1 1
      g711.c
  2. 165 0
      g721.c
  3. 532 0
      g72x.c
  4. 29 3
      virtual_portal.c

+ 1 - 1
g711.c

@@ -228,7 +228,7 @@ int ulaw2linear(unsigned char u_val)
     int t;
 
     /* Complement to obtain normal u-law value. */
-    // u_val = ~u_val;
+    u_val = ~u_val;
 
     /*
      * Extract and bias the quantization bits. Then

+ 165 - 0
g721.c

@@ -0,0 +1,165 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use.  Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * g721.c
+ *
+ * Description:
+ *
+ * g721_encoder(), g721_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.721 ADPCM
+ * coding algorithm.  Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which
+ * take advantage of work station attributes, such as hardware 2's
+ * complement arithmetic and large memory.  Specifically, certain time
+ * consuming operations such as multiplications are replaced
+ * with lookup tables and software 2's complement operations are
+ * replaced with hardware 2's complement.
+ *
+ * The deviation from the bit level specification (lookup tables)
+ * preserves the bit level performance specifications.
+ *
+ * As outlined in the G.721 Recommendation, the algorithm is broken
+ * down into modules.  Each section of code below is preceded by
+ * the name of the module which it is implementing.
+ *
+ */
+#include "g72x.h"
+
+static short qtab_721[7] = { -124, 80, 178, 246, 300, 349, 400 };
+/*
+ * Maps G.721 code word to reconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[16] = { -2048, 4,   135, 213, 273, 323, 373, 425,
+                              425,   373, 323, 273, 213, 135, 4,   -2048 };
+
+/* Maps G.721 code word to log of scale factor multiplier. */
+static short _witab[16] = { -12,  18,  41,  64,  112, 198, 355, 1122,
+                            1122, 355, 198, 112, 64,  41,  18,  -12 };
+/*
+ * Maps G.721 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[16] = { 0,     0,     0,     0x200, 0x200, 0x200, 0x600, 0xE00,
+                            0xE00, 0x600, 0x200, 0x200, 0x200, 0,     0,     0 };
+
+/*
+ * g721_encoder()
+ *
+ * Encodes the input vale of linear PCM, A-law or u-law data sl and returns
+ * the resulting code. -1 is returned for unknown input coding value.
+ */
+int g721_encoder(int sl, int in_coding, struct g72x_state* state_ptr)
+{
+    short sezi, se, sez; /* ACCUM */
+    short d;             /* SUBTA */
+    short sr;            /* ADDB */
+    short y;             /* MIX */
+    short dqsez;         /* ADDC */
+    short dq, i;
+
+    switch (in_coding) { /* linearize input sample to 14-bit PCM */
+    case AUDIO_ENCODING_ALAW:
+        sl = alaw2linear(sl) >> 2;
+        break;
+    case AUDIO_ENCODING_ULAW:
+        sl = ulaw2linear(sl) >> 2;
+        break;
+    case AUDIO_ENCODING_LINEAR:
+        sl >>= 2; /* 14-bit dynamic range */
+        break;
+    default:
+        return (-1);
+    }
+
+    sezi = predictor_zero(state_ptr);
+    sez = sezi >> 1;
+    se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */
+
+    d = sl - se; /* estimation difference */
+
+    /* quantize the prediction difference */
+    y = step_size(state_ptr);        /* quantizer step size */
+    i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */
+
+    dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */
+
+    sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */
+
+    dqsez = sr + sez - se; /* pole prediction diff. */
+
+    update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+    return (i);
+}
+
+/*
+ * g721_decoder()
+ *
+ * Description:
+ *
+ * Decodes a 4-bit code of G.721 encoded data of i and
+ * returns the resulting linear PCM, A-law or u-law value.
+ * return -1 for unknown out_coding value.
+ */
+int g721_decoder(int i, int out_coding, struct g72x_state* state_ptr)
+{
+    short sezi, sei, sez, se; /* ACCUM */
+    short y;                  /* MIX */
+    short sr;                 /* ADDB */
+    short dq;
+    short dqsez;
+
+    i &= 0x0f; /* mask to get proper bits */
+    sezi = predictor_zero(state_ptr);
+    sez = sezi >> 1;
+    sei = sezi + predictor_pole(state_ptr);
+    se = sei >> 1; /* se = estimated signal */
+
+    y = step_size(state_ptr); /* dynamic quantizer step size */
+
+    dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
+
+    sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
+
+    dqsez = sr - se + sez; /* pole prediction diff. */
+
+    update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+    switch (out_coding) {
+    case AUDIO_ENCODING_ALAW:
+        return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721));
+    case AUDIO_ENCODING_ULAW:
+        return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721));
+    case AUDIO_ENCODING_LINEAR:
+        return (sr << 2); /* sr was 14-bit dynamic range */
+    default:
+        return (-1);
+    }
+}

+ 532 - 0
g72x.c

@@ -0,0 +1,532 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use.  Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#include <stdlib.h>
+/*
+ * g72x.c
+ *
+ * Common routines for G.721 and G.723 conversions.
+ */
+
+#include "g72x.h"
+
+static short power2[15] = { 1,     2,     4,     8,     0x10,   0x20,   0x40,  0x80,
+                            0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 };
+
+/*
+ * quan()
+ *
+ * quantizes the input val against the table of size short integers.
+ * It returns i if table[i - 1] <= val < table[i].
+ *
+ * Using linear search for simple coding.
+ */
+static int quan(int val, short* table, int size)
+{
+    int i;
+
+    for (i = 0; i < size; i++)
+        if (val < *table++)
+            break;
+    return (i);
+}
+
+/*
+ * fmult()
+ *
+ * returns the integer product of the 14-bit integer "an" and
+ * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
+ */
+static int fmult(int an, int srn)
+{
+    short anmag, anexp, anmant;
+    short wanexp, wanmant;
+    short retval;
+
+    anmag = (an > 0) ? an : ((-an) & 0x1FFF);
+    anexp = quan(anmag, power2, 15) - 6;
+    anmant = (anmag == 0) ? 32 : (anexp >= 0) ? anmag >> anexp : anmag << -anexp;
+    wanexp = anexp + ((srn >> 6) & 0xF) - 13;
+
+    wanmant = (anmant * (srn & 077) + 0x30) >> 4;
+    retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : (wanmant >> -wanexp);
+
+    return (((an ^ srn) < 0) ? -retval : retval);
+}
+
+/*
+ * g72x_init_state()
+ *
+ * This routine initializes and/or resets the g72x_state structure
+ * pointed to by 'state_ptr'.
+ * All the initial state values are specified in the CCITT G.721 document.
+ */
+void g72x_init_state(struct g72x_state* state_ptr)
+{
+    int cnta;
+
+    state_ptr->yl = 34816;
+    state_ptr->yu = 544;
+    state_ptr->dms = 0;
+    state_ptr->dml = 0;
+    state_ptr->ap = 0;
+    for (cnta = 0; cnta < 2; cnta++) {
+        state_ptr->a[cnta] = 0;
+        state_ptr->pk[cnta] = 0;
+        state_ptr->sr[cnta] = 32;
+    }
+    for (cnta = 0; cnta < 6; cnta++) {
+        state_ptr->b[cnta] = 0;
+        state_ptr->dq[cnta] = 32;
+    }
+    state_ptr->td = 0;
+}
+
+/*
+ * predictor_zero()
+ *
+ * computes the estimated signal from 6-zero predictor.
+ *
+ */
+int predictor_zero(struct g72x_state* state_ptr)
+{
+    int i;
+    int sezi;
+
+    sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
+    for (i = 1; i < 6; i++) /* ACCUM */
+        sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
+    return (sezi);
+}
+/*
+ * predictor_pole()
+ *
+ * computes the estimated signal from 2-pole predictor.
+ *
+ */
+int predictor_pole(struct g72x_state* state_ptr)
+{
+    return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
+            fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
+}
+/*
+ * step_size()
+ *
+ * computes the quantization step size of the adaptive quantizer.
+ *
+ */
+int step_size(struct g72x_state* state_ptr)
+{
+    int y;
+    int dif;
+    int al;
+
+    if (state_ptr->ap >= 256)
+        return (state_ptr->yu);
+    else {
+        y = state_ptr->yl >> 6;
+        dif = state_ptr->yu - y;
+        al = state_ptr->ap >> 2;
+        if (dif > 0)
+            y += (dif * al) >> 6;
+        else if (dif < 0)
+            y += (dif * al + 0x3F) >> 6;
+        return (y);
+    }
+}
+
+/*
+ * quantize()
+ *
+ * Given a raw sample, 'd', of the difference signal and a
+ * quantization step size scale factor, 'y', this routine returns the
+ * ADPCM codeword to which that sample gets quantized.  The step
+ * size scale factor division operation is done in the log base 2 domain
+ * as a subtraction.
+ */
+int quantize(int d,        /* Raw difference signal sample */
+             int y,        /* Step size multiplier */
+             short* table, /* quantization table */
+             int size)     /* table size of short integers */
+{
+    short dqm;  /* Magnitude of 'd' */
+    short exp;  /* Integer part of base 2 log of 'd' */
+    short mant; /* Fractional part of base 2 log */
+    short dl;   /* Log of magnitude of 'd' */
+    short dln;  /* Step size scale factor normalized log */
+    int i;
+
+    /*
+     * LOG
+     *
+     * Compute base 2 log of 'd', and store in 'dl'.
+     */
+    dqm = abs(d);
+    exp = quan(dqm >> 1, power2, 15);
+    mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */
+    dl = (exp << 7) + mant;
+
+    /*
+     * SUBTB
+     *
+     * "Divide" by step size multiplier.
+     */
+    dln = dl - (y >> 2);
+
+    /*
+     * QUAN
+     *
+     * Obtain codword i for 'd'.
+     */
+    i = quan(dln, table, size);
+    if (d < 0) /* take 1's complement of i */
+        return ((size << 1) + 1 - i);
+    else if (i == 0)              /* take 1's complement of 0 */
+        return ((size << 1) + 1); /* new in 1988 */
+    else
+        return (i);
+}
+/*
+ * reconstruct()
+ *
+ * Returns reconstructed difference signal 'dq' obtained from
+ * codeword 'i' and quantization step size scale factor 'y'.
+ * Multiplication is performed in log base 2 domain as addition.
+ */
+int reconstruct(int sign, /* 0 for non-negative value */
+                int dqln, /* G.72x codeword */
+                int y)    /* Step size multiplier */
+{
+    short dql; /* Log of 'dq' magnitude */
+    short dex; /* Integer part of log */
+    short dqt;
+    short dq; /* Reconstructed difference signal sample */
+
+    dql = dqln + (y >> 2); /* ADDA */
+
+    if (dql < 0) {
+        return ((sign) ? -0x8000 : 0);
+    } else { /* ANTILOG */
+        dex = (dql >> 7) & 15;
+        dqt = 128 + (dql & 127);
+        dq = (dqt << 7) >> (14 - dex);
+        return ((sign) ? (dq - 0x8000) : dq);
+    }
+}
+
+
+/*
+ * update()
+ *
+ * updates the state variables for each output code
+ */
+void update(int code_size,                /* distinguish 723_40 with others */
+            int y,                        /* quantizer step size */
+            int wi,                       /* scale factor multiplier */
+            int fi,                       /* for long/short term energies */
+            int dq,                       /* quantized prediction difference */
+            int sr,                       /* reconstructed signal */
+            int dqsez,                    /* difference from 2-pole predictor */
+            struct g72x_state* state_ptr) /* coder state pointer */
+{
+    int cnt;
+    short mag, exp; /* Adaptive predictor, FLOAT A */
+    short a2p = 0;  /* LIMC */
+    short a1ul;     /* UPA1 */
+    short pks1;     /* UPA2 */
+    short fa1;
+    char tr; /* tone/transition detector */
+    short ylint, thr2, dqthr;
+    short ylfrac, thr1;
+    short pk0;
+
+    pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
+
+    mag = dq & 0x7FFF; /* prediction difference magnitude */
+    /* TRANS */
+    ylint = state_ptr->yl >> 15;           /* exponent part of yl */
+    ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
+    thr1 = (32 + ylfrac) << ylint;         /* threshold */
+    thr2 = (ylint > 9) ? 31 << 10 : thr1;  /* limit thr2 to 31 << 10 */
+    dqthr = (thr2 + (thr2 >> 1)) >> 1;     /* dqthr = 0.75 * thr2 */
+    if (state_ptr->td == 0)                /* signal supposed voice */
+        tr = 0;
+    else if (mag <= dqthr) /* supposed data, but small mag */
+        tr = 0;            /* treated as voice */
+    else                   /* signal is data (modem) */
+        tr = 1;
+
+    /*
+     * Quantizer scale factor adaptation.
+     */
+
+    /* FUNCTW & FILTD & DELAY */
+    /* update non-steady state step size multiplier */
+    state_ptr->yu = y + ((wi - y) >> 5);
+
+    /* LIMB */
+    if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
+        state_ptr->yu = 544;
+    else if (state_ptr->yu > 5120)
+        state_ptr->yu = 5120;
+
+    /* FILTE & DELAY */
+    /* update steady state step size multiplier */
+    state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
+
+    /*
+     * Adaptive predictor coefficients.
+     */
+    if (tr == 1) { /* reset a's and b's for modem signal */
+        state_ptr->a[0] = 0;
+        state_ptr->a[1] = 0;
+        state_ptr->b[0] = 0;
+        state_ptr->b[1] = 0;
+        state_ptr->b[2] = 0;
+        state_ptr->b[3] = 0;
+        state_ptr->b[4] = 0;
+        state_ptr->b[5] = 0;
+    } else {                           /* update a's and b's */
+        pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
+
+        /* update predictor pole a[1] */
+        a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
+        if (dqsez != 0) {
+            fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
+            if (fa1 < -8191) /* a2p = function of fa1 */
+                a2p -= 0x100;
+            else if (fa1 > 8191)
+                a2p += 0xFF;
+            else
+                a2p += fa1 >> 5;
+
+            if (pk0 ^ state_ptr->pk[1])
+                /* LIMC */
+                if (a2p <= -12160)
+                    a2p = -12288;
+                else if (a2p >= 12416)
+                    a2p = 12288;
+                else
+                    a2p -= 0x80;
+            else if (a2p <= -12416)
+                a2p = -12288;
+            else if (a2p >= 12160)
+                a2p = 12288;
+            else
+                a2p += 0x80;
+        }
+
+        /* TRIGB & DELAY */
+        state_ptr->a[1] = a2p;
+
+        /* UPA1 */
+        /* update predictor pole a[0] */
+        state_ptr->a[0] -= state_ptr->a[0] >> 8;
+        if (dqsez != 0) {
+            if (pks1 == 0)
+                state_ptr->a[0] += 192;
+            else
+                state_ptr->a[0] -= 192;
+        }
+
+        /* LIMD */
+        a1ul = 15360 - a2p;
+        if (state_ptr->a[0] < -a1ul)
+            state_ptr->a[0] = -a1ul;
+        else if (state_ptr->a[0] > a1ul)
+            state_ptr->a[0] = a1ul;
+
+        /* UPB : update predictor zeros b[6] */
+        for (cnt = 0; cnt < 6; cnt++) {
+            if (code_size == 5) /* for 40Kbps G.723 */
+                state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
+            else /* for G.721 and 24Kbps G.723 */
+                state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
+            if (dq & 0x7FFF) { /* XOR */
+                if ((dq ^ state_ptr->dq[cnt]) >= 0)
+                    state_ptr->b[cnt] += 128;
+                else
+                    state_ptr->b[cnt] -= 128;
+            }
+        }
+    }
+
+    for (cnt = 5; cnt > 0; cnt--)
+        state_ptr->dq[cnt] = state_ptr->dq[cnt - 1];
+    /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
+    if (mag == 0) {
+        state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
+    } else {
+        exp = quan(mag, power2, 15);
+        state_ptr->dq[0] = (dq >= 0) ? (exp << 6) + ((mag << 6) >> exp)
+                                     : (exp << 6) + ((mag << 6) >> exp) - 0x400;
+    }
+
+    state_ptr->sr[1] = state_ptr->sr[0];
+    /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
+    if (sr == 0) {
+        state_ptr->sr[0] = 0x20;
+    } else if (sr > 0) {
+        exp = quan(sr, power2, 15);
+        state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
+    } else if (sr > -32768) {
+        mag = -sr;
+        exp = quan(mag, power2, 15);
+        state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
+    } else
+        state_ptr->sr[0] = 0xFC20;
+
+    /* DELAY A */
+    state_ptr->pk[1] = state_ptr->pk[0];
+    state_ptr->pk[0] = pk0;
+
+    /* TONE */
+    if (tr == 1)           /* this sample has been treated as data */
+        state_ptr->td = 0; /* next one will be treated as voice */
+    else if (a2p < -11776) /* small sample-to-sample correlation */
+        state_ptr->td = 1; /* signal may be data */
+    else                   /* signal is voice */
+        state_ptr->td = 0;
+
+    /*
+     * Adaptation speed control.
+     */
+    state_ptr->dms += (fi - state_ptr->dms) >> 5;          /* FILTA */
+    state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
+
+    if (tr == 1)
+        state_ptr->ap = 256;
+    else if (y < 1536) /* SUBTC */
+        state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+    else if (state_ptr->td == 1)
+        state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+    else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= (state_ptr->dml >> 3))
+        state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+    else
+        state_ptr->ap += (-state_ptr->ap) >> 4;
+}
+
+/*
+ * tandem_adjust(sr, se, y, i, sign)
+ *
+ * At the end of ADPCM decoding, it simulates an encoder which may be receiving
+ * the output of this decoder as a tandem process. If the output of the
+ * simulated encoder differs from the input to this decoder, the decoder output
+ * is adjusted by one level of A-law or u-law codes.
+ *
+ * Input:
+ *	sr	decoder output linear PCM sample,
+ *	se	predictor estimate sample,
+ *	y	quantizer step size,
+ *	i	decoder input code,
+ *	sign	sign bit of code i
+ *
+ * Return:
+ *	adjusted A-law or u-law compressed sample.
+ */
+int tandem_adjust_alaw(int sr, /* decoder output linear PCM sample */
+                       int se, /* predictor estimate sample */
+                       int y,  /* quantizer step size */
+                       int i,  /* decoder input code */
+                       int sign,
+                       short* qtab)
+{
+    unsigned char sp; /* A-law compressed 8-bit code */
+    short dx;         /* prediction error */
+    char id;          /* quantized prediction error */
+    int sd;           /* adjusted A-law decoded sample value */
+    int im;           /* biased magnitude of i */
+    int imx;          /* biased magnitude of id */
+
+    if (sr <= -32768)
+        sr = -1;
+    sp = linear2alaw((sr >> 1) << 3); /* short to A-law compression */
+    dx = (alaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
+    id = quantize(dx, y, qtab, sign - 1);
+
+    if (id == i) { /* no adjustment on sp */
+        return (sp);
+    } else { /* sp adjustment needed */
+        /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
+        im = i ^ sign; /* 2's complement to biased unsigned */
+        imx = id ^ sign;
+
+        if (imx > im) { /* sp adjusted to next lower value */
+            if (sp & 0x80) {
+                sd = (sp == 0xD5) ? 0x55 : ((sp ^ 0x55) - 1) ^ 0x55;
+            } else {
+                sd = (sp == 0x2A) ? 0x2A : ((sp ^ 0x55) + 1) ^ 0x55;
+            }
+        } else { /* sp adjusted to next higher value */
+            if (sp & 0x80)
+                sd = (sp == 0xAA) ? 0xAA : ((sp ^ 0x55) + 1) ^ 0x55;
+            else
+                sd = (sp == 0x55) ? 0xD5 : ((sp ^ 0x55) - 1) ^ 0x55;
+        }
+        return (sd);
+    }
+}
+
+int tandem_adjust_ulaw(int sr, /* decoder output linear PCM sample */
+                       int se, /* predictor estimate sample */
+                       int y,  /* quantizer step size */
+                       int i,  /* decoder input code */
+                       int sign,
+                       short* qtab)
+{
+    unsigned char sp; /* u-law compressed 8-bit code */
+    short dx;         /* prediction error */
+    char id;          /* quantized prediction error */
+    int sd;           /* adjusted u-law decoded sample value */
+    int im;           /* biased magnitude of i */
+    int imx;          /* biased magnitude of id */
+
+    if (sr <= -32768)
+        sr = 0;
+    sp = linear2ulaw(sr << 2);        /* short to u-law compression */
+    dx = (ulaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
+    id = quantize(dx, y, qtab, sign - 1);
+    if (id == i) {
+        return (sp);
+    } else {
+        /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
+        im = i ^ sign; /* 2's complement to biased unsigned */
+        imx = id ^ sign;
+        if (imx > im) { /* sp adjusted to next lower value */
+            if (sp & 0x80)
+                sd = (sp == 0xFF) ? 0x7E : sp + 1;
+            else
+                sd = (sp == 0) ? 0 : sp - 1;
+
+        } else { /* sp adjusted to next higher value */
+            if (sp & 0x80)
+                sd = (sp == 0x80) ? 0x80 : sp - 1;
+            else
+                sd = (sp == 0x7F) ? 0xFE : sp + 1;
+        }
+        return (sd);
+    }
+}
+

+ 29 - 3
virtual_portal.c

@@ -222,7 +222,8 @@ VirtualPortal* virtual_portal_alloc(NotificationApp* notifications) {
 void virtual_portal_set_type(VirtualPortal* virtual_portal, PoFType type) {
     virtual_portal->type = type;
     if (furi_hal_speaker_acquire(1000)) {
-        wav_player_speaker_init(virtual_portal->type == PoFHid ? 8000 : 4000);
+        // wav_player_speaker_init(virtual_portal->type == PoFHid ? 8000 : 4000);
+        wav_player_speaker_init(8000);
         wav_player_dma_init((uint32_t)virtual_portal->audio_buffer, SAMPLES_COUNT);
 
         furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, wav_player_dma_isr, virtual_portal);
@@ -403,7 +404,7 @@ int virtual_portal_send_status(VirtualPortal* virtual_portal, uint8_t* response)
     }
     return 0;
 }
-
+struct g72x_state state;
 // 4d01ff0000d0077d6c2a77a400000000
 int virtual_portal_m(VirtualPortal* virtual_portal, uint8_t* message, uint8_t* response) {
     virtual_portal->speaker = (message[1] == 1);
@@ -421,6 +422,7 @@ int virtual_portal_m(VirtualPortal* virtual_portal, uint8_t* message, uint8_t* r
     response[index++] = message[1];
     response[index++] = 0x00;
     response[index++] = 0x19;
+    g72x_init_state(&state);
     return index;
 }
 
@@ -578,7 +580,7 @@ void virtual_portal_process_audio_360(
     uint8_t len) {
     for (size_t i = 0; i < len; i++) {
         
-        int16_t int_16 = (int16_t)alaw2linear(message[i]);
+        int16_t int_16 = (int16_t)g721_decoder(message[i],AUDIO_ENCODING_LINEAR, &state);
 
         float data = ((float)int_16 / 256.0);
         data /= UINT8_MAX / 2;  // scale -1..1
@@ -601,6 +603,30 @@ void virtual_portal_process_audio_360(
         if (++virtual_portal->head == virtual_portal->end) {
             virtual_portal->head = virtual_portal->current_audio_buffer;
         }
+
+        // int_16 = (int16_t)g721_decoder(message[i] << 4,AUDIO_ENCODING_LINEAR, &state);
+
+        // data = ((float)int_16 / 256.0);
+        // data /= UINT8_MAX / 2;  // scale -1..1
+
+        // data *= virtual_portal->volume;  // volume
+        // data = tanhf(data);              // hyperbolic tangent limiter
+
+        // data *= UINT8_MAX / 2;  // scale -128..127
+        // data += UINT8_MAX / 2;  // to unsigned
+
+        // if (data < 0) {
+        //     data = 0;
+        // }
+
+        // if (data > 255) {
+        //     data = 255;
+        // }
+        // *virtual_portal->head = data;
+        // virtual_portal->count++;
+        // if (++virtual_portal->head == virtual_portal->end) {
+        //     virtual_portal->head = virtual_portal->current_audio_buffer;
+        // }
     }
 }