From aeb0cdb9fb3c122f19a59142ae3d6b8c4e239286 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 21 May 2002 18:31:36 +0000 Subject: [PATCH] Implemented a G711 ACM codec (supports both A-Law and MU-Law). --- dlls/Makefile.in | 11 +- dlls/msacm/msg711/.cvsignore | 4 +- dlls/msacm/msg711/Makefile.in | 3 +- dlls/msacm/msg711/msg711.acm.spec | 4 + dlls/msacm/msg711/msg711.c | 1163 ++++++++++++++++++++++++++++- dlls/msacm/msg711/msg711.drv.spec | 4 - 6 files changed, 1176 insertions(+), 13 deletions(-) create mode 100644 dlls/msacm/msg711/msg711.acm.spec delete mode 100644 dlls/msacm/msg711/msg711.drv.spec diff --git a/dlls/Makefile.in b/dlls/Makefile.in index c4cc327e210..c61475f62b0 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -156,7 +156,7 @@ all: \ msacm.drv$(DLLEXT) \ msacm32.dll$(DLLEXT) \ msdmo.dll$(DLLEXT) \ - msg711.drv$(DLLEXT) \ + msg711.acm$(DLLEXT) \ msimg32.dll$(DLLEXT) \ msisys.ocx$(DLLEXT) \ msnet32.dll$(DLLEXT) \ @@ -349,8 +349,8 @@ msacm32.dll$(DLLEXT) msacm.dll$(DLLEXT): msacm/msacm32.dll$(DLLEXT) msdmo.dll$(DLLEXT): msdmo/msdmo.dll$(DLLEXT) $(RM) $@ && $(LN_S) msdmo/msdmo.dll$(DLLEXT) $@ -msg711.drv$(DLLEXT): msacm/msg711/msg711.drv$(DLLEXT) - $(RM) $@ && $(LN_S) msacm/msg711/msg711.drv$(DLLEXT) $@ +msg711.acm$(DLLEXT): msacm/msg711/msg711.acm$(DLLEXT) + $(RM) $@ && $(LN_S) msacm/msg711/msg711.acm$(DLLEXT) $@ msimg32.dll$(DLLEXT): msimg32/msimg32.dll$(DLLEXT) $(RM) $@ && $(LN_S) msimg32/msimg32.dll$(DLLEXT) $@ @@ -605,8 +605,9 @@ msacm/msacm32.dll$(DLLEXT): dummy winmm.dll$(DLLEXT) user32.dll$(DLLEXT) \ advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) @cd msacm && $(MAKE) msacm32.dll$(DLLEXT) -msacm/msg711/msg711.drv$(DLLEXT): dummy kernel32.dll$(DLLEXT) - @cd msacm/msg711 && $(MAKE) msg711.drv$(DLLEXT) +msacm/msg711/msg711.acm$(DLLEXT): dummy winmm.dll$(DLLEXT) user32.dll$(DLLEXT) \ + kernel32.dll$(DLLEXT) + @cd msacm/msg711 && $(MAKE) msg711.acm$(DLLEXT) msdmo/msdmo.dll$(DLLEXT): dummy kernel32.dll$(DLLEXT) @cd msdmo && $(MAKE) msdmo.dll$(DLLEXT) diff --git a/dlls/msacm/msg711/.cvsignore b/dlls/msacm/msg711/.cvsignore index b75bb72c1f6..722ed61224d 100644 --- a/dlls/msacm/msg711/.cvsignore +++ b/dlls/msacm/msg711/.cvsignore @@ -1,3 +1,3 @@ Makefile -msg711.drv.dbg.c -msg711.drv.spec.c +msg711.acm.dbg.c +msg711.acm.spec.c diff --git a/dlls/msacm/msg711/Makefile.in b/dlls/msacm/msg711/Makefile.in index c6495f73c61..24b4ee3d2e3 100644 --- a/dlls/msacm/msg711/Makefile.in +++ b/dlls/msacm/msg711/Makefile.in @@ -2,7 +2,8 @@ TOPSRCDIR = @top_srcdir@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ -MODULE = msg711.drv +MODULE = msg711.acm +IMPORTS = winmm user32 kernel32 LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o diff --git a/dlls/msacm/msg711/msg711.acm.spec b/dlls/msacm/msg711/msg711.acm.spec new file mode 100644 index 00000000000..407f3ae6956 --- /dev/null +++ b/dlls/msacm/msg711/msg711.acm.spec @@ -0,0 +1,4 @@ +name msg711 +file msg711.acm + +@ stdcall DriverProc(long long long long long) G711_DriverProc diff --git a/dlls/msacm/msg711/msg711.c b/dlls/msacm/msg711/msg711.c index f67dd033a4d..696bb368555 100644 --- a/dlls/msacm/msg711/msg711.c +++ b/dlls/msacm/msg711/msg711.c @@ -1 +1,1162 @@ -/* all codes are removed by author */ +/* + * 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 +#include +#include "winnls.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "msacm.h" +#include "mmreg.h" +#include "../msacmdrv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(g711); + +/*********************************************************************** + * G711_drvOpen + */ +static DWORD G711_drvOpen(LPCSTR str) +{ + return 1; +} + +/*********************************************************************** + * G711_drvClose + */ +static DWORD G711_drvClose(DWORD 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 = (HICON)0; + 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 WCHAR szPcm[]={'P','C','M',0}; + static WCHAR szALaw[]={'A','-','L','a','w',0}; + static 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_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 = 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 dwDevID, HDRVR hDriv, UINT wMsg, + LPARAM dwParam1, LPARAM dwParam2) +{ + TRACE("(%08lx %08lx %04x %08lx %08lx);\n", + dwDevID, (DWORD)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); + } + return 0; +} diff --git a/dlls/msacm/msg711/msg711.drv.spec b/dlls/msacm/msg711/msg711.drv.spec deleted file mode 100644 index d03bb631e4a..00000000000 --- a/dlls/msacm/msg711/msg711.drv.spec +++ /dev/null @@ -1,4 +0,0 @@ -name msg711 -file msg711.drv - -@ stub DriverProc #(long long long long long)