Logo Search packages:      
Sourcecode: wine version File versions  Download package

msg711.c

/*
 * G711 handling (includes A-Law & MU-Law)
 *
 *      Copyright (C) 2002          Eric Pouech
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "mmsystem.h"
#include "mmreg.h"
#include "msacm.h"
#include "msacmdrv.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(g711);

/***********************************************************************
 *           G711_drvOpen
 */
static LRESULT G711_drvOpen(LPCSTR str)
{
    return 1;
}

/***********************************************************************
 *           G711_drvClose
 */
static LRESULT G711_drvClose(DWORD_PTR dwDevID)
{
    return 1;
}

typedef struct tagAcmG711Data
{
    void (*convert)(PACMDRVSTREAMINSTANCE adsi,
                const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
} AcmG711Data;

/* table to list all supported formats... those are the basic ones. this
 * also helps given a unique index to each of the supported formats
 */
typedef     struct
{
    int           nChannels;
    int           nBits;
    int           rate;
} Format;

static Format PCM_Formats[] =
{
    /*{1,  8,  8000}, {2,  8,  8000}, */{1, 16,  8000}, {2, 16,  8000},
    /*{1,  8, 11025}, {2,  8, 11025}, */{1, 16, 11025}, {2, 16, 11025},
    /*{1,  8, 22050}, {2,  8, 22050}, */{1, 16, 22050}, {2, 16, 22050},
    /*{1,  8, 44100}, {2,  8, 44100}, */{1, 16, 44100}, {2, 16, 44100},
};

static Format ALaw_Formats[] =
{
    {1,  8,  8000}, {2, 8,  8000},  {1,  8, 11025}, {2,      8, 11025},
    {1,  8, 22050}, {2, 8, 22050},  {1,  8, 44100}, {2,      8, 44100},
};

static Format ULaw_Formats[] =
{
    {1,  8,  8000}, {2, 8,  8000},  {1,  8, 11025}, {2,      8, 11025},
    {1,  8, 22050}, {2, 8, 22050},  {1,  8, 44100}, {2,      8, 44100},
};

#define     NUM_PCM_FORMATS         (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
#define     NUM_ALAW_FORMATS  (sizeof(ALaw_Formats) / sizeof(ALaw_Formats[0]))
#define     NUM_ULAW_FORMATS  (sizeof(ULaw_Formats) / sizeof(ULaw_Formats[0]))

/***********************************************************************
 *           G711_GetFormatIndex
 */
static      DWORD G711_GetFormatIndex(LPWAVEFORMATEX wfx)
{
    int     i, hi;
    Format* fmts;

    switch (wfx->wFormatTag)
    {
    case WAVE_FORMAT_PCM:
      hi = NUM_PCM_FORMATS;
      fmts = PCM_Formats;
      break;
    case WAVE_FORMAT_ALAW:
      hi = NUM_ALAW_FORMATS;
      fmts = ALaw_Formats;
      break;
    case WAVE_FORMAT_MULAW:
      hi = NUM_ULAW_FORMATS;
      fmts = ULaw_Formats;
      break;
    default:
      return 0xFFFFFFFF;
    }

    for (i = 0; i < hi; i++)
    {
      if (wfx->nChannels == fmts[i].nChannels &&
          wfx->nSamplesPerSec == fmts[i].rate &&
          wfx->wBitsPerSample == fmts[i].nBits)
          return i;
    }

    return 0xFFFFFFFF;
}

/***********************************************************************
 *           R16
 *
 * Read a 16 bit sample (correctly handles endianess)
 */
static inline short  R16(const unsigned char* src)
{
    return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
}

/***********************************************************************
 *           W16
 *
 * Write a 16 bit sample (correctly handles endianess)
 */
static inline void  W16(unsigned char* dst, short s)
{
    dst[0] = LOBYTE(s);
    dst[1] = HIBYTE(s);
}

/* You can uncomment this if you don't want the statically generated conversion
 * table, but rather recompute the Xlaw => PCM conversion for each sample
#define NO_FASTDECODE
 * Since the conversion tables are rather small (2k), I don't think it's really
 * interesting not to use them, but keeping the actual conversion code around
 * is helpful to regenerate the tables when needed.
 */

/* -------------------------------------------------------------------------------*/

/*
 * 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
 */

/*
 * g711.c
 *
 * u-law, A-law and linear PCM conversions.
 */

/*
 * December 30, 1994:
 * Functions linear2alaw, linear2ulaw have been updated to correctly
 * convert unquantized 16 bit values.
 * Tables for direct u- to A-law and A- to u-law conversions have been
 * corrected.
 * Borge Lindberg, Center for PersonKommunikation, Aalborg University.
 * bli@cpk.auc.dk
 *
 */

#define     SIGN_BIT    (0x80)            /* Sign bit for a A-law byte. */
#define     QUANT_MASK  (0xf)       /* Quantization field mask. */
#define     NSEGS       (8)         /* Number of A-law segments. */
#define     SEG_SHIFT   (4)         /* Left shift for segment number. */
#define     SEG_MASK    (0x70)            /* Segment field mask. */

static short seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
                      0x1FF, 0x3FF, 0x7FF, 0xFFF};
static short seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
                      0x3FF, 0x7FF, 0xFFF, 0x1FFF};

/* copy from CCITT G.711 specifications */
static unsigned char _u2a[128] = {              /* u- to A-law conversions */
      1,    1,    2,    2,    3,    3,    4,    4,
      5,    5,    6,    6,    7,    7,    8,    8,
      9,    10,   11,   12,   13,   14,   15,   16,
      17,   18,   19,   20,   21,   22,   23,   24,
      25,   27,   29,   31,   33,   34,   35,   36,
      37,   38,   39,   40,   41,   42,   43,   44,
      46,   48,   49,   50,   51,   52,   53,   54,
      55,   56,   57,   58,   59,   60,   61,   62,
      64,   65,   66,   67,   68,   69,   70,   71,
      72,   73,   74,   75,   76,   77,   78,   79,
/* corrected:
      81,   82,   83,   84,   85,   86,   87,   88,
   should be: */
      80,   82,   83,   84,   85,   86,   87,   88,
      89,   90,   91,   92,   93,   94,   95,   96,
      97,   98,   99,   100,  101,  102,  103,  104,
      105,  106,  107,  108,  109,  110,  111,  112,
      113,  114,  115,  116,  117,  118,  119,  120,
      121,  122,  123,  124,  125,  126,  127,  128};

static unsigned char _a2u[128] = {              /* A- to u-law conversions */
      1,    3,    5,    7,    9,    11,   13,   15,
      16,   17,   18,   19,   20,   21,   22,   23,
      24,   25,   26,   27,   28,   29,   30,   31,
      32,   32,   33,   33,   34,   34,   35,   35,
      36,   37,   38,   39,   40,   41,   42,   43,
      44,   45,   46,   47,   48,   48,   49,   49,
      50,   51,   52,   53,   54,   55,   56,   57,
      58,   59,   60,   61,   62,   63,   64,   64,
      65,   66,   67,   68,   69,   70,   71,   72,
/* corrected:
      73,   74,   75,   76,   77,   78,   79,   79,
   should be: */
      73,   74,   75,   76,   77,   78,   79,   80,

      80,   81,   82,   83,   84,   85,   86,   87,
      88,   89,   90,   91,   92,   93,   94,   95,
      96,   97,   98,   99,   100,  101,  102,  103,
      104,  105,  106,  107,  108,  109,  110,  111,
      112,  113,  114,  115,  116,  117,  118,  119,
      120,  121,  122,  123,  124,  125,  126,  127};

static short
search(
    int           val,          /* changed from "short" *drago* */
    short   *table,
    int           size)         /* changed from "short" *drago* */
{
    int           i;    /* changed from "short" *drago* */

    for (i = 0; i < size; i++) {
        if (val <= *table++)
            return (i);
    }
    return (size);
}

/*
 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
 *
 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
 *
 *          Linear Input Code Compressed Code
 *    ------------------------      ---------------
 *    0000000wxyza                  000wxyz
 *    0000001wxyza                  001wxyz
 *    000001wxyzab                  010wxyz
 *    00001wxyzabc                  011wxyz
 *    0001wxyzabcd                  100wxyz
 *    001wxyzabcde                  101wxyz
 *    01wxyzabcdef                  110wxyz
 *    1wxyzabcdefg                  111wxyz
 *
 * For further information see John C. Bellamy's Digital Telephony, 1982,
 * John Wiley & Sons, pps 98-111 and 472-476.
 */
static inline unsigned char
linear2alaw(int pcm_val)      /* 2's complement (16-bit range) */
    /* changed from "short" *drago* */
{
    int           mask; /* changed from "short" *drago* */
    int           seg;  /* changed from "short" *drago* */
    unsigned char aval;

    pcm_val = pcm_val >> 3;

    if (pcm_val >= 0) {
        mask = 0xD5;          /* sign (7th) bit = 1 */
    } else {
        mask = 0x55;          /* sign bit = 0 */
        pcm_val = -pcm_val - 1;
    }

    /* Convert the scaled magnitude to segment number. */
    seg = search(pcm_val, seg_aend, 8);

    /* Combine the sign, segment, and quantization bits. */

    if (seg >= 8)       /* out of range, return maximum value. */
        return (unsigned char) (0x7F ^ mask);
    else {
        aval = (unsigned char) seg << SEG_SHIFT;
        if (seg < 2)
            aval |= (pcm_val >> 1) & QUANT_MASK;
        else
            aval |= (pcm_val >> seg) & QUANT_MASK;
        return (aval ^ mask);
    }
}

#ifdef NO_FASTDECODE
/*
 * alaw2linear() - Convert an A-law value to 16-bit linear PCM
 *
 */
static inline int
alaw2linear(unsigned char a_val)
{
    int           t;    /* changed from "short" *drago* */
    int           seg;  /* changed from "short" *drago* */

    a_val ^= 0x55;

    t = (a_val & QUANT_MASK) << 4;
    seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
    switch (seg) {
    case 0:
        t += 8;
        break;
    case 1:
        t += 0x108;
        break;
    default:
        t += 0x108;
        t <<= seg - 1;
    }
    return ((a_val & SIGN_BIT) ? t : -t);
}
#else
/* EPP (for Wine):
 * this array has been statically generated from the above routine
 */
static unsigned short _a2l[] = {
0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80,
0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0,
0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600,
0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00,
0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8,
0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8,
0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60,
0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0,
0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280,
0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940,
0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00,
0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500,
0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128,
0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028,
0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0,
0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250,
0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350,
};
static int inline
alaw2linear(unsigned char a_val)
{
    return (short)_a2l[a_val];
}
#endif

#define     BIAS        (0x84)            /* Bias for linear code. */
#define CLIP            8159

/*
 * linear2ulaw() - Convert a linear PCM value to u-law
 *
 * In order to simplify the encoding process, the original linear magnitude
 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
 * (33 - 8191). The result can be seen in the following encoding table:
 *
 *    Biased Linear Input Code      Compressed Code
 *    ------------------------      ---------------
 *    00000001wxyza                 000wxyz
 *    0000001wxyzab                 001wxyz
 *    000001wxyzabc                 010wxyz
 *    00001wxyzabcd                 011wxyz
 *    0001wxyzabcde                 100wxyz
 *    001wxyzabcdef                 101wxyz
 *    01wxyzabcdefg                 110wxyz
 *    1wxyzabcdefgh                 111wxyz
 *
 * Each biased linear code has a leading 1 which identifies the segment
 * number. The value of the segment number is equal to 7 minus the number
 * of leading 0's. The quantization interval is directly available as the
 * four bits wxyz.  * The trailing bits (a - h) are ignored.
 *
 * Ordinarily the complement of the resulting code word is used for
 * transmission, and so the code word is complemented before it is returned.
 *
 * For further information see John C. Bellamy's Digital Telephony, 1982,
 * John Wiley & Sons, pps 98-111 and 472-476.
 */
static inline unsigned char
linear2ulaw(short pcm_val)    /* 2's complement (16-bit range) */
{
    short         mask;
    short         seg;
    unsigned char uval;

    /* Get the sign and the magnitude of the value. */
    pcm_val = pcm_val >> 2;
    if (pcm_val < 0) {
        pcm_val = -pcm_val;
        mask = 0x7F;
    } else {
        mask = 0xFF;
    }
    if ( pcm_val > CLIP ) pcm_val = CLIP;       /* clip the magnitude */
    pcm_val += (BIAS >> 2);

    /* Convert the scaled magnitude to segment number. */
    seg = search(pcm_val, seg_uend, 8);

    /*
     * Combine the sign, segment, quantization bits;
     * and complement the code word.
     */
    if (seg >= 8)       /* out of range, return maximum value. */
        return (unsigned char) (0x7F ^ mask);
    else {
        uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
        return (uval ^ mask);
    }
}

#ifdef NO_FASTDECODE
/*
 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
 *
 * First, a biased linear code is derived from the code word. An unbiased
 * output can then be obtained by subtracting 33 from the biased code.
 *
 * Note that this function expects to be passed the complement of the
 * original code word. This is in keeping with ISDN conventions.
 */
static inline short
ulaw2linear(unsigned char u_val)
{
    short         t;

    /* Complement to obtain normal u-law value. */
    u_val = ~u_val;

    /*
     * Extract and bias the quantization bits. Then
     * shift up by the segment number and subtract out the bias.
     */
    t = ((u_val & QUANT_MASK) << 3) + BIAS;
    t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;

    return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
}
#else
/* EPP (for Wine):
 * this array has been statically generated from the above routine
 */
static unsigned short _u2l[] = {
0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84,
0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84,
0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804,
0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444,
0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64,
0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74,
0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC,
0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0,
0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C,
0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C,
0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC,
0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC,
0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C,
0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C,
0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000,
};
static inline short ulaw2linear(unsigned char u_val)
{
    return (short)_u2l[u_val];
}
#endif

/* A-law to u-law conversion */
static inline unsigned char
alaw2ulaw(unsigned char aval)
{
    aval &= 0xff;
    return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
                            (0x7F ^ _a2u[aval ^ 0x55]));
}

/* u-law to A-law conversion */
static inline unsigned char
ulaw2alaw(unsigned char uval)
{
    uval &= 0xff;
    return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
                            (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
}

/* -------------------------------------------------------------------------------*/

static void cvtXXalaw16K(PACMDRVSTREAMINSTANCE adsi,
                         const unsigned char* src, LPDWORD srcsize,
                         unsigned char* dst, LPDWORD dstsize)
{
    DWORD       len = min(*srcsize, *dstsize / 2);
    DWORD       i;
    short       w;

    *srcsize = len;
    *dstsize = len * 2;
    for (i = 0; i < len; i++)
    {
        w = alaw2linear(*src++);
        W16(dst, w);    dst += 2;
    }
}

static void cvtXX16alawK(PACMDRVSTREAMINSTANCE adsi,
                         const unsigned char* src, LPDWORD srcsize,
                         unsigned char* dst, LPDWORD dstsize)
{
    DWORD       len = min(*srcsize / 2, *dstsize);
    DWORD       i;

    *srcsize = len * 2;
    *dstsize = len;
    for (i = 0; i < len; i++)
    {
        *dst++ = linear2alaw(R16(src)); src += 2;
    }
}

static void cvtXXulaw16K(PACMDRVSTREAMINSTANCE adsi,
                         const unsigned char* src, LPDWORD srcsize,
                         unsigned char* dst, LPDWORD dstsize)
{
    DWORD       len = min(*srcsize, *dstsize / 2);
    DWORD       i;
    short       w;

    *srcsize = len;
    *dstsize = len * 2;
    for (i = 0; i < len; i++)
    {
        w = ulaw2linear(*src++);
        W16(dst, w);    dst += 2;
    }
}

static void cvtXX16ulawK(PACMDRVSTREAMINSTANCE adsi,
                         const unsigned char* src, LPDWORD srcsize,
                         unsigned char* dst, LPDWORD dstsize)
{
    DWORD       len = min(*srcsize / 2, *dstsize);
    DWORD       i;

    *srcsize = len * 2;
    *dstsize = len;
    for (i = 0; i < len; i++)
    {
        *dst++ = linear2ulaw(R16(src)); src += 2;
    }
}

static void cvtXXalawulawK(PACMDRVSTREAMINSTANCE adsi,
                           const unsigned char* src, LPDWORD srcsize,
                           unsigned char* dst, LPDWORD dstsize)
{
    DWORD       len = min(*srcsize, *dstsize);
    DWORD       i;

    *srcsize = len;
    *dstsize = len;

    for (i = 0; i < len; i++)
        *dst++ = alaw2ulaw(*src++);
}


static void cvtXXulawalawK(PACMDRVSTREAMINSTANCE adsi,
                           const unsigned char* src, LPDWORD srcsize,
                           unsigned char* dst, LPDWORD dstsize)
{
    DWORD       len = min(*srcsize, *dstsize);
    DWORD       i;

    *srcsize = len;
    *dstsize = len;

    for (i = 0; i < len; i++)
        *dst++ = ulaw2alaw(*src++);
}

/***********************************************************************
 *           G711_DriverDetails
 *
 */
static      LRESULT G711_DriverDetails(PACMDRIVERDETAILSW add)
{
    add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
    add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
    add->wMid = 0xFF;
    add->wPid = 0x00;
    add->vdwACM = 0x01000000;
    add->vdwDriver = 0x01000000;
    add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
    add->cFormatTags = 3; /* PCM, G711 A-LAW & MU-LAW */
    add->cFilterTags = 0;
    add->hicon = NULL;
    MultiByteToWideChar( CP_ACP, 0, "WINE-G711", -1,
                         add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
    MultiByteToWideChar( CP_ACP, 0, "Wine G711 converter", -1,
                         add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
    MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
                         add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
    MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
                         add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
    add->szFeatures[0] = 0;

    return MMSYSERR_NOERROR;
}

/***********************************************************************
 *           G711_FormatTagDetails
 *
 */
static      LRESULT     G711_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
{
    static const WCHAR szPcm[]={'P','C','M',0};
    static const WCHAR szALaw[]={'A','-','L','a','w',0};
    static const WCHAR szULaw[]={'U','-','L','a','w',0};

    switch (dwQuery)
    {
    case ACM_FORMATTAGDETAILSF_INDEX:
      if (aftd->dwFormatTagIndex >= 3) return ACMERR_NOTPOSSIBLE;
      break;
    case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
      if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
        {
            aftd->dwFormatTagIndex = 1;
          break;
      }
      /* fall thru */
    case ACM_FORMATTAGDETAILSF_FORMATTAG:
      switch (aftd->dwFormatTag)
        {
      case WAVE_FORMAT_PCM:   aftd->dwFormatTagIndex = 0; break;
      case WAVE_FORMAT_ALAW:  aftd->dwFormatTagIndex = 1; break;
      case WAVE_FORMAT_MULAW: aftd->dwFormatTagIndex = 2; break;
      default:          return ACMERR_NOTPOSSIBLE;
      }
      break;
    default:
      WARN("Unsupported query %08lx\n", dwQuery);
      return MMSYSERR_NOTSUPPORTED;
    }

    aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
    switch (aftd->dwFormatTagIndex)
    {
    case 0:
      aftd->dwFormatTag = WAVE_FORMAT_PCM;
      aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
      aftd->cStandardFormats = NUM_PCM_FORMATS;
        lstrcpyW(aftd->szFormatTag, szPcm);
        break;
    case 1:
      aftd->dwFormatTag = WAVE_FORMAT_ALAW;
      aftd->cbFormatSize = sizeof(WAVEFORMATEX);
      aftd->cStandardFormats = NUM_ALAW_FORMATS;
        lstrcpyW(aftd->szFormatTag, szALaw);
      break;
    case 2:
      aftd->dwFormatTag = WAVE_FORMAT_MULAW;
      aftd->cbFormatSize = sizeof(WAVEFORMATEX);
      aftd->cStandardFormats = NUM_ULAW_FORMATS;
        lstrcpyW(aftd->szFormatTag, szULaw);
      break;
    }
    return MMSYSERR_NOERROR;
}

/***********************************************************************
 *           G711_FormatDetails
 *
 */
static      LRESULT     G711_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
{
    switch (dwQuery)
    {
    case ACM_FORMATDETAILSF_FORMAT:
      if (G711_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
      break;
    case ACM_FORMATDETAILSF_INDEX:
      afd->pwfx->wFormatTag = afd->dwFormatTag;
      switch (afd->dwFormatTag)
        {
      case WAVE_FORMAT_PCM:
          if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
          afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
          afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
          afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
          afd->pwfx->nBlockAlign = afd->pwfx->nChannels * 2;
          afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
          break;
      case WAVE_FORMAT_ALAW:
          if (afd->dwFormatIndex >= NUM_ALAW_FORMATS) return ACMERR_NOTPOSSIBLE;
          afd->pwfx->nChannels = ALaw_Formats[afd->dwFormatIndex].nChannels;
          afd->pwfx->nSamplesPerSec = ALaw_Formats[afd->dwFormatIndex].rate;
          afd->pwfx->wBitsPerSample = ALaw_Formats[afd->dwFormatIndex].nBits;
          afd->pwfx->nBlockAlign = ALaw_Formats[afd->dwFormatIndex].nChannels;
          afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * afd->pwfx->nChannels;
            afd->pwfx->cbSize = 0;
          break;
      case WAVE_FORMAT_MULAW:
          if (afd->dwFormatIndex >= NUM_ULAW_FORMATS) return ACMERR_NOTPOSSIBLE;
          afd->pwfx->nChannels = ULaw_Formats[afd->dwFormatIndex].nChannels;
          afd->pwfx->nSamplesPerSec = ULaw_Formats[afd->dwFormatIndex].rate;
          afd->pwfx->wBitsPerSample = ULaw_Formats[afd->dwFormatIndex].nBits;
          afd->pwfx->nBlockAlign = ULaw_Formats[afd->dwFormatIndex].nChannels;
          afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * afd->pwfx->nChannels;
            afd->pwfx->cbSize = 0;
          break;
      default:
          WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
          return MMSYSERR_INVALPARAM;
      }
      break;
    default:
      WARN("Unsupported query %08lx\n", dwQuery);
      return MMSYSERR_NOTSUPPORTED;
    }
    afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
    afd->szFormat[0] = 0; /* let MSACM format this for us... */

    return MMSYSERR_NOERROR;
}

/***********************************************************************
 *           G711_FormatSuggest
 *
 */
static      LRESULT     G711_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
{
    /* some tests ... */
    if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
      adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
      G711_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
    /* FIXME: should do those tests against the real size (according to format tag */

    /* If no suggestion for destination, then copy source value */
    if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
      adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
    if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
        adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;

    if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
    {
      if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
            adfs->pwfxDst->wBitsPerSample = 8;
        else
            adfs->pwfxDst->wBitsPerSample = 16;
    }
    if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
    {
      switch (adfs->pwfxSrc->wFormatTag)
        {
        case WAVE_FORMAT_PCM:   adfs->pwfxDst->wFormatTag = WAVE_FORMAT_ALAW; break;
        case WAVE_FORMAT_ALAW:  adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; break;
        case WAVE_FORMAT_MULAW: adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; break;
        }
    }
    /* check if result is ok */
    if (G711_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;

    /* recompute other values */
    switch (adfs->pwfxDst->wFormatTag)
    {
    case WAVE_FORMAT_PCM:
        adfs->pwfxDst->nBlockAlign = adfs->pwfxDst->nChannels;
        adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
        break;
    case WAVE_FORMAT_ALAW:
        adfs->pwfxDst->nBlockAlign = adfs->pwfxDst->nChannels * 2;
        adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxSrc->nChannels * 2;
        break;
    case WAVE_FORMAT_MULAW:
        adfs->pwfxDst->nBlockAlign =  adfs->pwfxDst->nChannels * 2;
        adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxSrc->nChannels * 2;
        break;
    default:
        FIXME("\n");
        break;
    }

    return MMSYSERR_NOERROR;
}

/***********************************************************************
 *           G711_Reset
 *
 */
static      void  G711_Reset(PACMDRVSTREAMINSTANCE adsi, AcmG711Data* aad)
{
}

/***********************************************************************
 *           G711_StreamOpen
 *
 */
static      LRESULT     G711_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
{
    AcmG711Data*  aad;

    assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));

    if (G711_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
      G711_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
      return ACMERR_NOTPOSSIBLE;

    aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmG711Data));
    if (aad == 0) return MMSYSERR_NOMEM;

    adsi->dwDriver = (DWORD)aad;

    if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
      adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
    {
      goto theEnd;
    }
    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ALAW &&
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
    {
      /* resampling or mono <=> stereo not available
         * G711 algo only define 16 bit per sample output
         */
      if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
          adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
            adsi->pwfxDst->wBitsPerSample != 16)
          goto theEnd;

      /* g711 A-Law decoding... */
      if (adsi->pwfxDst->wBitsPerSample == 16)
          aad->convert = cvtXXalaw16K;
    }
    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ALAW)
    {
      if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
          adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
            adsi->pwfxSrc->wBitsPerSample != 16)
          goto theEnd;

      /* g711 coding... */
      if (adsi->pwfxSrc->wBitsPerSample == 16)
          aad->convert = cvtXX16alawK;
    }
    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MULAW &&
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
    {
      /* resampling or mono <=> stereo not available
         * G711 algo only define 16 bit per sample output
         */
      if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
          adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
            adsi->pwfxDst->wBitsPerSample != 16)
          goto theEnd;

      /* g711 MU-Law decoding... */
      if (adsi->pwfxDst->wBitsPerSample == 16)
          aad->convert = cvtXXulaw16K;
    }
    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MULAW)
    {
      if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
          adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
            adsi->pwfxSrc->wBitsPerSample != 16)
          goto theEnd;

      /* g711 coding... */
      if (adsi->pwfxSrc->wBitsPerSample == 16)
          aad->convert = cvtXX16ulawK;
    }
    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MULAW &&
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ALAW)
    {
      if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
          adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels)
          goto theEnd;

      /* MU-Law => A-Law... */
        aad->convert = cvtXXulawalawK;
    }
    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ALAW &&
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MULAW)
    {
      if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
          adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels)
          goto theEnd;

      /* A-Law => MU-Law... */
        aad->convert = cvtXXalawulawK;
    }
    else goto theEnd;

    G711_Reset(adsi, aad);

    return MMSYSERR_NOERROR;

 theEnd:
    HeapFree(GetProcessHeap(), 0, aad);
    adsi->dwDriver = 0L;
    return MMSYSERR_NOTSUPPORTED;
}

/***********************************************************************
 *           G711_StreamClose
 *
 */
static      LRESULT     G711_StreamClose(PACMDRVSTREAMINSTANCE adsi)
{
    HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
    return MMSYSERR_NOERROR;
}

/***********************************************************************
 *           G711_round
 *
 */
static      inline DWORD      G711_round(DWORD a, DWORD b, DWORD c)
{
    assert(a && b && c);
    /* to be sure, always return an entire number of c... */
    return ((double)a * (double)b + (double)c - 1) / (double)c;
}

/***********************************************************************
 *           G711_StreamSize
 *
 */
static      LRESULT G711_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
{
    switch (adss->fdwSize)
    {
    case ACM_STREAMSIZEF_DESTINATION:
      /* cbDstLength => cbSrcLength */
      if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
          (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ALAW ||
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MULAW))
        {
          adss->cbSrcLength = adss->cbDstLength / 2;
      }
        else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ALAW ||
                  adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MULAW) &&
                 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
        {
          adss->cbSrcLength = adss->cbDstLength * 2;
      }
        else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ALAW ||
                  adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MULAW) &&
                 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ALAW ||
                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MULAW))
        {
          adss->cbSrcLength = adss->cbDstLength;
        }
        else
        {
          return MMSYSERR_NOTSUPPORTED;
      }
      break;
    case ACM_STREAMSIZEF_SOURCE:
      /* cbSrcLength => cbDstLength */
      if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
          (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ALAW ||
             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MULAW))
        {
          adss->cbDstLength = adss->cbSrcLength * 2;
      }
        else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ALAW ||
                  adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MULAW) &&
                 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
        {
          adss->cbDstLength = adss->cbSrcLength / 2;
      }
        else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ALAW ||
                  adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MULAW) &&
                 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ALAW ||
                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MULAW))
        {
          adss->cbDstLength = adss->cbSrcLength;
        }
        else
        {
          return MMSYSERR_NOTSUPPORTED;
      }
      break;
    default:
      WARN("Unsupported query %08lx\n", adss->fdwSize);
      return MMSYSERR_NOTSUPPORTED;
    }
    FIXME("\n");
    return MMSYSERR_NOERROR;
}

/***********************************************************************
 *           G711_StreamConvert
 *
 */
static LRESULT G711_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
{
    AcmG711Data*  aad = (AcmG711Data*)adsi->dwDriver;
    DWORD         nsrc = adsh->cbSrcLength;
    DWORD         ndst = adsh->cbDstLength;

    if (adsh->fdwConvert &
      ~(ACM_STREAMCONVERTF_BLOCKALIGN|
        ACM_STREAMCONVERTF_END|
        ACM_STREAMCONVERTF_START))
    {
      FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
    }
    /* ACM_STREAMCONVERTF_BLOCKALIGN
     *      currently all conversions are block aligned, so do nothing for this flag
     * ACM_STREAMCONVERTF_END
     *      no pending data, so do nothing for this flag
     */
    if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
    {
      G711_Reset(adsi, aad);
    }

    aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
    adsh->cbSrcLengthUsed = nsrc;
    adsh->cbDstLengthUsed = ndst;

    return MMSYSERR_NOERROR;
}

/**************************************************************************
 *                G711_DriverProc               [exported]
 */
LRESULT CALLBACK G711_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
                               LPARAM dwParam1, LPARAM dwParam2)
{
    TRACE("(%08lx %p %04x %08lx %08lx);\n",
          dwDevID, hDriv, wMsg, dwParam1, dwParam2);

    switch (wMsg)
    {
    case DRV_LOAD:            return 1;
    case DRV_FREE:            return 1;
    case DRV_OPEN:            return G711_drvOpen((LPSTR)dwParam1);
    case DRV_CLOSE:           return G711_drvClose(dwDevID);
    case DRV_ENABLE:          return 1;
    case DRV_DISABLE:         return 1;
    case DRV_QUERYCONFIGURE:  return 1;
    case DRV_CONFIGURE:       MessageBoxA(0, "MS G711 (a-Law & mu-Law) filter !", "Wine Driver", MB_OK); return 1;
    case DRV_INSTALL:         return DRVCNF_RESTART;
    case DRV_REMOVE:          return DRVCNF_RESTART;

    case ACMDM_DRIVER_NOTIFY:
      /* no caching from other ACM drivers is done so far */
      return MMSYSERR_NOERROR;

    case ACMDM_DRIVER_DETAILS:
      return G711_DriverDetails((PACMDRIVERDETAILSW)dwParam1);

    case ACMDM_FORMATTAG_DETAILS:
      return G711_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);

    case ACMDM_FORMAT_DETAILS:
      return G711_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);

    case ACMDM_FORMAT_SUGGEST:
      return G711_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);

    case ACMDM_STREAM_OPEN:
      return G711_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);

    case ACMDM_STREAM_CLOSE:
      return G711_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);

    case ACMDM_STREAM_SIZE:
      return G711_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);

    case ACMDM_STREAM_CONVERT:
      return G711_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);

    case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
    case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
      /* this converter is not a hardware driver */
    case ACMDM_FILTERTAG_DETAILS:
    case ACMDM_FILTER_DETAILS:
      /* this converter is not a filter */
    case ACMDM_STREAM_RESET:
      /* only needed for asynchronous driver... we aren't, so just say it */
      return MMSYSERR_NOTSUPPORTED;
    case ACMDM_STREAM_PREPARE:
    case ACMDM_STREAM_UNPREPARE:
      /* nothing special to do here... so don't do anything */
      return MMSYSERR_NOERROR;

    default:
      return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
    }
}

Generated by  Doxygen 1.6.0   Back to index