Release 9.12.
[wine.git] / dlls / msgsm32.acm / msgsm32.c
blob002604f0450b8f192a5093543d4960b1c7af43c6
1 /*
2 * GSM 06.10 codec handling
3 * Copyright (C) 2009 Maarten Lankhorst
5 * Based on msg711.acm
6 * Copyright (C) 2002 Eric Pouech
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <string.h>
27 #include <gsm.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "mmsystem.h"
35 #include "mmreg.h"
36 #include "msacm.h"
37 #include "msacmdrv.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(gsm);
43 /***********************************************************************
44 * GSM_DriverDetails
47 static LRESULT GSM_DriverDetails(PACMDRIVERDETAILSW add)
49 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
50 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
51 /* Details found from probing native msgsm32.acm */
52 add->wMid = MM_MICROSOFT;
53 add->wPid = MM_MSFT_ACM_GSM610;
54 add->vdwACM = 0x3320000;
55 add->vdwDriver = 0x4000000;
56 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
57 add->cFormatTags = 2;
58 add->cFilterTags = 0;
59 add->hicon = NULL;
60 MultiByteToWideChar( CP_ACP, 0, "Microsoft GSM 6.10", -1,
61 add->szShortName, ARRAY_SIZE( add->szShortName ));
62 MultiByteToWideChar( CP_ACP, 0, "Wine GSM 6.10 libgsm codec", -1,
63 add->szLongName, ARRAY_SIZE( add->szLongName ));
64 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
65 add->szCopyright, ARRAY_SIZE( add->szCopyright ));
66 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
67 add->szLicensing, ARRAY_SIZE( add->szLicensing ));
68 add->szFeatures[0] = 0;
69 return MMSYSERR_NOERROR;
72 /* Validate a WAVEFORMATEX structure */
73 static BOOL GSM_FormatValidate(const WAVEFORMATEX *wfx)
75 if (wfx->nChannels != 1)
76 return FALSE;
78 switch (wfx->wFormatTag)
80 case WAVE_FORMAT_PCM:
81 if (wfx->wBitsPerSample != 16)
83 WARN("PCM wBitsPerSample %u\n", wfx->wBitsPerSample);
84 return FALSE;
86 if (wfx->nBlockAlign != 2)
88 WARN("PCM nBlockAlign %u\n", wfx->nBlockAlign);
89 return FALSE;
91 if (wfx->nAvgBytesPerSec != wfx->nBlockAlign * wfx->nSamplesPerSec)
93 WARN("PCM nAvgBytesPerSec %lu/%lu\n",
94 wfx->nAvgBytesPerSec,
95 wfx->nBlockAlign * wfx->nSamplesPerSec);
96 return FALSE;
98 return TRUE;
99 case WAVE_FORMAT_GSM610:
100 if (wfx->cbSize < sizeof(WORD))
102 WARN("GSM cbSize %u\n", wfx->cbSize);
103 return FALSE;
105 if (wfx->wBitsPerSample != 0)
107 WARN("GSM wBitsPerSample %u\n", wfx->wBitsPerSample);
108 return FALSE;
110 if (wfx->nBlockAlign != 65)
112 WARN("GSM nBlockAlign %u\n", wfx->nBlockAlign);
113 return FALSE;
115 if (((const GSM610WAVEFORMAT*)wfx)->wSamplesPerBlock != 320)
117 WARN("GSM wSamplesPerBlock %u\n",
118 ((const GSM610WAVEFORMAT*)wfx)->wSamplesPerBlock);
119 return FALSE;
121 if (wfx->nAvgBytesPerSec != wfx->nSamplesPerSec * 65 / 320)
123 WARN("GSM nAvgBytesPerSec %ld / %ld\n",
124 wfx->nAvgBytesPerSec, wfx->nSamplesPerSec * 65 / 320);
125 return FALSE;
127 return TRUE;
128 default:
129 return FALSE;
131 return FALSE;
134 static const DWORD gsm_rates[] = { 8000, 11025, 22050, 44100, 48000, 96000 };
136 /***********************************************************************
137 * GSM_FormatTagDetails
140 static LRESULT GSM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
142 static const WCHAR szPcm[]={'P','C','M',0};
143 static const WCHAR szGsm[]={'G','S','M',' ','6','.','1','0',0};
145 switch (dwQuery)
147 case ACM_FORMATTAGDETAILSF_INDEX:
148 if (aftd->dwFormatTagIndex > 1) return ACMERR_NOTPOSSIBLE;
149 break;
150 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
151 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
153 aftd->dwFormatTagIndex = 1;
154 break;
156 /* fall through */
157 case ACM_FORMATTAGDETAILSF_FORMATTAG:
158 switch (aftd->dwFormatTag)
160 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
161 case WAVE_FORMAT_GSM610: aftd->dwFormatTagIndex = 1; break;
162 default: return ACMERR_NOTPOSSIBLE;
164 break;
165 default:
166 WARN("Unsupported query %08lx\n", dwQuery);
167 return MMSYSERR_NOTSUPPORTED;
170 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
171 switch (aftd->dwFormatTagIndex)
173 case 0:
174 aftd->dwFormatTag = WAVE_FORMAT_PCM;
175 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
176 aftd->cStandardFormats = ARRAY_SIZE(gsm_rates);
177 lstrcpyW(aftd->szFormatTag, szPcm);
178 break;
179 case 1:
180 aftd->dwFormatTag = WAVE_FORMAT_GSM610;
181 aftd->cbFormatSize = sizeof(GSM610WAVEFORMAT);
182 aftd->cStandardFormats = ARRAY_SIZE(gsm_rates);
183 lstrcpyW(aftd->szFormatTag, szGsm);
184 break;
186 return MMSYSERR_NOERROR;
189 /***********************************************************************
190 * GSM_FormatDetails
193 static LRESULT GSM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
195 switch (dwQuery)
197 case ACM_FORMATDETAILSF_FORMAT:
198 if (!GSM_FormatValidate(afd->pwfx)) return ACMERR_NOTPOSSIBLE;
199 break;
200 case ACM_FORMATDETAILSF_INDEX:
201 afd->pwfx->wFormatTag = afd->dwFormatTag;
202 switch (afd->dwFormatTag)
204 case WAVE_FORMAT_PCM:
205 if (afd->dwFormatIndex >= ARRAY_SIZE(gsm_rates)) return ACMERR_NOTPOSSIBLE;
206 afd->pwfx->nChannels = 1;
207 afd->pwfx->nSamplesPerSec = gsm_rates[afd->dwFormatIndex];
208 afd->pwfx->wBitsPerSample = 16;
209 afd->pwfx->nBlockAlign = 2;
210 afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
211 break;
212 case WAVE_FORMAT_GSM610:
213 if (afd->dwFormatIndex >= ARRAY_SIZE(gsm_rates)) return ACMERR_NOTPOSSIBLE;
214 afd->pwfx->nChannels = 1;
215 afd->pwfx->nSamplesPerSec = gsm_rates[afd->dwFormatIndex];
216 afd->pwfx->wBitsPerSample = 0;
217 afd->pwfx->nBlockAlign = 65;
218 afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * 65 / 320;
219 afd->pwfx->cbSize = sizeof(WORD);
220 ((GSM610WAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = 320;
221 break;
222 default:
223 WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
224 return MMSYSERR_INVALPARAM;
226 break;
227 default:
228 WARN("Unsupported query %08lx\n", dwQuery);
229 return MMSYSERR_NOTSUPPORTED;
231 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
232 afd->szFormat[0] = 0; /* let MSACM format this for us... */
234 return MMSYSERR_NOERROR;
237 /***********************************************************************
238 * GSM_FormatSuggest
241 static LRESULT GSM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
243 /* some tests ... */
244 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
245 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
246 !GSM_FormatValidate(adfs->pwfxSrc)) return ACMERR_NOTPOSSIBLE;
247 /* FIXME: should do those tests against the real size (according to format tag */
249 /* If no suggestion for destination, then copy source value */
250 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
251 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
252 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
253 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
255 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
257 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
258 adfs->pwfxDst->wBitsPerSample = 0;
259 else
260 adfs->pwfxDst->wBitsPerSample = 16;
262 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
264 switch (adfs->pwfxSrc->wFormatTag)
266 case WAVE_FORMAT_PCM: adfs->pwfxDst->wFormatTag = WAVE_FORMAT_GSM610; break;
267 case WAVE_FORMAT_GSM610: adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; break;
271 /* recompute other values */
272 switch (adfs->pwfxDst->wFormatTag)
274 case WAVE_FORMAT_PCM:
275 adfs->pwfxDst->nBlockAlign = 2;
276 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * 2;
277 break;
278 case WAVE_FORMAT_GSM610:
279 if (adfs->pwfxDst->cbSize < sizeof(WORD))
280 return ACMERR_NOTPOSSIBLE;
281 adfs->pwfxDst->nBlockAlign = 65;
282 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * 65 / 320;
283 ((GSM610WAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock = 320;
284 break;
285 default:
286 return ACMERR_NOTPOSSIBLE;
289 /* check if result is ok */
290 if (!GSM_FormatValidate(adfs->pwfxDst)) return ACMERR_NOTPOSSIBLE;
291 return MMSYSERR_NOERROR;
294 /***********************************************************************
295 * GSM_StreamOpen
298 static LRESULT GSM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
300 int used = 1;
301 gsm r;
302 if (adsi->pwfxSrc->wFormatTag != WAVE_FORMAT_GSM610 && adsi->pwfxDst->wFormatTag != WAVE_FORMAT_GSM610)
303 return MMSYSERR_NOTSUPPORTED;
305 if (!GSM_FormatValidate(adsi->pwfxSrc) || !GSM_FormatValidate(adsi->pwfxDst))
306 return MMSYSERR_NOTSUPPORTED;
308 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec)
309 return MMSYSERR_NOTSUPPORTED;
311 r = gsm_create();
312 if (!r)
313 return MMSYSERR_NOMEM;
314 if (gsm_option(r, GSM_OPT_WAV49, &used) < 0)
316 FIXME("Your libgsm library doesn't support GSM_OPT_WAV49\n");
317 FIXME("Please recompile libgsm with WAV49 support\n");
318 gsm_destroy(r);
319 return MMSYSERR_NOTSUPPORTED;
321 adsi->dwDriver = (DWORD_PTR)r;
322 return MMSYSERR_NOERROR;
325 /***********************************************************************
326 * GSM_StreamClose
329 static LRESULT GSM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
331 gsm_destroy((gsm)adsi->dwDriver);
332 return MMSYSERR_NOERROR;
335 /***********************************************************************
336 * GSM_StreamSize
339 static LRESULT GSM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
341 switch (adss->fdwSize)
343 case ACM_STREAMSIZEF_DESTINATION:
344 /* cbDstLength => cbSrcLength */
345 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
346 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_GSM610)
348 adss->cbSrcLength = adss->cbDstLength / 65 * 640;
350 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_GSM610 &&
351 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
353 adss->cbSrcLength = adss->cbDstLength / 640 * 65;
355 else
357 return MMSYSERR_NOTSUPPORTED;
359 return MMSYSERR_NOERROR;
360 case ACM_STREAMSIZEF_SOURCE:
361 /* cbSrcLength => cbDstLength */
362 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
363 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_GSM610)
365 adss->cbDstLength = (adss->cbSrcLength + 639) / 640 * 65;
367 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_GSM610 &&
368 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
370 adss->cbDstLength = adss->cbSrcLength / 65 * 640;
372 else
374 return MMSYSERR_NOTSUPPORTED;
376 return MMSYSERR_NOERROR;
377 default:
378 WARN("Unsupported query %08lx\n", adss->fdwSize);
379 return MMSYSERR_NOTSUPPORTED;
383 /***********************************************************************
384 * GSM_StreamConvert
387 static LRESULT GSM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
389 gsm r = (gsm)adsi->dwDriver;
390 DWORD nsrc = 0;
391 DWORD ndst = 0;
392 BYTE *src = adsh->pbSrc;
393 BYTE *dst = adsh->pbDst;
394 int odd = 0;
396 if (adsh->fdwConvert &
397 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
398 ACM_STREAMCONVERTF_END|
399 ACM_STREAMCONVERTF_START))
401 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
404 /* Reset the index to 0, just to be sure */
405 gsm_option(r, GSM_OPT_FRAME_INDEX, &odd);
407 /* The native ms codec writes 65 bytes, and this requires 2 libgsm calls.
408 * First 32 bytes are written, or 33 bytes read
409 * Second 33 bytes are written, or 32 bytes read
412 /* Decode */
413 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_GSM610)
415 if (adsh->cbSrcLength / 65 * 640 > adsh->cbDstLength)
417 return ACMERR_NOTPOSSIBLE;
420 while (nsrc + 65 <= adsh->cbSrcLength)
422 /* Decode data */
423 if (gsm_decode(r, src + nsrc, (gsm_signal*)(dst + ndst)) < 0)
424 FIXME("Couldn't decode data\n");
425 ndst += 320;
426 nsrc += 33;
428 if (gsm_decode(r, src + nsrc, (gsm_signal*)(dst + ndst)) < 0)
429 FIXME("Couldn't decode data\n");
430 ndst += 320;
431 nsrc += 32;
434 else
436 /* Testing a little seems to reveal that despite being able to fit
437 * inside the buffer if ACM_STREAMCONVERTF_BLOCKALIGN is set
438 * it still rounds up
440 if ((adsh->cbSrcLength + 639) / 640 * 65 > adsh->cbDstLength)
442 return ACMERR_NOTPOSSIBLE;
445 /* The packing algorithm writes 32 bytes, then 33 bytes,
446 * and it seems to pad to align to 65 bytes always
447 * adding extra data where necessary
449 while (nsrc + 640 <= adsh->cbSrcLength)
451 /* Encode data */
452 gsm_encode(r, (gsm_signal*)(src+nsrc), dst+ndst);
453 nsrc += 320;
454 ndst += 32;
455 gsm_encode(r, (gsm_signal*)(src+nsrc), dst+ndst);
456 nsrc += 320;
457 ndst += 33;
460 /* If ACM_STREAMCONVERTF_BLOCKALIGN isn't set pad with zeros */
461 if (!(adsh->fdwConvert & ACM_STREAMCONVERTF_BLOCKALIGN) &&
462 nsrc < adsh->cbSrcLength)
464 char emptiness[320];
465 int todo = adsh->cbSrcLength - nsrc;
467 if (todo > 320)
469 gsm_encode(r, (gsm_signal*)(src+nsrc), dst+ndst);
470 ndst += 32;
471 todo -= 320;
472 nsrc += 320;
474 memcpy(emptiness, src+nsrc, todo);
475 memset(emptiness + todo, 0, 320 - todo);
476 gsm_encode(r, (gsm_signal*)emptiness, dst+ndst);
477 ndst += 33;
479 else
481 memcpy(emptiness, src+nsrc, todo);
482 memset(emptiness + todo, 0, 320 - todo);
483 gsm_encode(r, (gsm_signal*)emptiness, dst+ndst);
484 ndst += 32;
486 memset(emptiness, 0, todo);
487 gsm_encode(r, (gsm_signal*)emptiness, dst+ndst);
488 ndst += 33;
490 nsrc = adsh->cbSrcLength;
494 adsh->cbSrcLengthUsed = nsrc;
495 adsh->cbDstLengthUsed = ndst;
496 TRACE("%ld(%ld) -> %ld(%ld)\n", nsrc, adsh->cbSrcLength, ndst, adsh->cbDstLength);
497 return MMSYSERR_NOERROR;
500 /**************************************************************************
501 * GSM_DriverProc [exported]
503 LRESULT CALLBACK GSM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
504 LPARAM dwParam1, LPARAM dwParam2)
506 TRACE("(%08Ix %p %04x %08Ix %08Ix);\n",
507 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
509 switch (wMsg)
511 case DRV_LOAD: return 1;
512 case DRV_FREE: return 1;
513 case DRV_OPEN: return 1;
514 case DRV_CLOSE: return 1;
515 case DRV_ENABLE: return 1;
516 case DRV_DISABLE: return 1;
517 case DRV_QUERYCONFIGURE: return 1;
518 case DRV_CONFIGURE: MessageBoxA(0, "GSM 06.10 codec", "Wine Driver", MB_OK); return 1;
519 case DRV_INSTALL: return DRVCNF_RESTART;
520 case DRV_REMOVE: return DRVCNF_RESTART;
522 case ACMDM_DRIVER_NOTIFY:
523 /* no caching from other ACM drivers is done so far */
524 return MMSYSERR_NOERROR;
526 case ACMDM_DRIVER_DETAILS:
527 return GSM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
529 case ACMDM_FORMATTAG_DETAILS:
530 return GSM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
532 case ACMDM_FORMAT_DETAILS:
533 return GSM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
535 case ACMDM_FORMAT_SUGGEST:
536 return GSM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
538 case ACMDM_STREAM_OPEN:
539 return GSM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
541 case ACMDM_STREAM_CLOSE:
542 return GSM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
544 case ACMDM_STREAM_SIZE:
545 return GSM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
547 case ACMDM_STREAM_CONVERT:
548 return GSM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
550 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
551 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
552 /* this converter is not a hardware driver */
553 case ACMDM_FILTERTAG_DETAILS:
554 case ACMDM_FILTER_DETAILS:
555 /* this converter is not a filter */
556 case ACMDM_STREAM_RESET:
557 /* only needed for asynchronous driver... we aren't, so just say it */
558 return MMSYSERR_NOTSUPPORTED;
559 case ACMDM_STREAM_PREPARE:
560 case ACMDM_STREAM_UNPREPARE:
561 /* nothing special to do here... so don't do anything */
562 return MMSYSERR_NOERROR;
564 default:
565 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);