1 | /* -*- tab-width: 8; c-basic-offset: 4 -*- */
|
---|
2 | /* $Id: pcmconverter.c,v 1.2 2001-09-05 13:11:26 bird Exp $ */
|
---|
3 | /*
|
---|
4 | * MSACM32 library
|
---|
5 | *
|
---|
6 | * Copyright 2000 Eric Pouech
|
---|
7 | *
|
---|
8 | * FIXME / TODO list
|
---|
9 | * + most of the computation should be done in fixed point arithmetic
|
---|
10 | * instead of floating point (16 bits for integral part, and 16 bits
|
---|
11 | * for fractional part for example)
|
---|
12 | * + implement PCM_FormatSuggest function
|
---|
13 | * + get rid of hack for PCM_DriverProc (msacm32.dll shouldn't export
|
---|
14 | * a DriverProc, but this would require implementing a generic
|
---|
15 | * embedded driver handling scheme in msacm32.dll which isn't done yet
|
---|
16 | */
|
---|
17 |
|
---|
18 | #include <assert.h>
|
---|
19 | #include <string.h>
|
---|
20 | #include "winnls.h"
|
---|
21 | #include "winbase.h"
|
---|
22 | #include "wingdi.h"
|
---|
23 | #include "winuser.h"
|
---|
24 | #include "msacm.h"
|
---|
25 | #include "msacmdrv.h"
|
---|
26 | #include "debugtools.h"
|
---|
27 |
|
---|
28 | #ifdef __WIN32OS2__
|
---|
29 | #define inline
|
---|
30 | #endif
|
---|
31 |
|
---|
32 | DEFAULT_DEBUG_CHANNEL(msacm);
|
---|
33 |
|
---|
34 | /***********************************************************************
|
---|
35 | * PCM_drvOpen
|
---|
36 | */
|
---|
37 | static DWORD PCM_drvOpen(LPCSTR str)
|
---|
38 | {
|
---|
39 | return 1;
|
---|
40 | }
|
---|
41 |
|
---|
42 | /***********************************************************************
|
---|
43 | * PCM_drvClose
|
---|
44 | */
|
---|
45 | static DWORD PCM_drvClose(DWORD dwDevID)
|
---|
46 | {
|
---|
47 | return 1;
|
---|
48 | }
|
---|
49 |
|
---|
50 | #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
|
---|
51 | #define NUM_OF(a,b) (((a)+(b)-1)/(b))
|
---|
52 |
|
---|
53 | /* flags for fdwDriver */
|
---|
54 | #define PCM_RESAMPLE 1
|
---|
55 |
|
---|
56 | /* data used while converting */
|
---|
57 | typedef struct tagAcmPcmData {
|
---|
58 | /* conversion routine, depending if rate conversion is required */
|
---|
59 | union {
|
---|
60 | void (*cvtKeepRate)(const unsigned char*, int, unsigned char*);
|
---|
61 | void (*cvtChangeRate)(struct tagAcmPcmData*, const unsigned char*,
|
---|
62 | LPDWORD, unsigned char*, LPDWORD);
|
---|
63 | } cvt;
|
---|
64 | /* the following fields are used only with rate conversion) */
|
---|
65 | DWORD srcPos; /* position in source stream */
|
---|
66 | double dstPos; /* position in destination stream */
|
---|
67 | double dstIncr; /* value to increment dst stream when src stream
|
---|
68 | is incremented by 1 */
|
---|
69 | /* last source stream value read */
|
---|
70 | union {
|
---|
71 | unsigned char b; /* 8 bit value */
|
---|
72 | short s; /* 16 bit value */
|
---|
73 | } last[2]; /* two channels max (stereo) */
|
---|
74 | } AcmPcmData;
|
---|
75 |
|
---|
76 | /* table to list all supported formats... those are the basic ones. this
|
---|
77 | * also helps given a unique index to each of the supported formats
|
---|
78 | */
|
---|
79 | static struct {
|
---|
80 | int nChannels;
|
---|
81 | int nBits;
|
---|
82 | int rate;
|
---|
83 | } PCM_Formats[] = {
|
---|
84 | {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
|
---|
85 | {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
|
---|
86 | {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
|
---|
87 | {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
|
---|
88 | };
|
---|
89 |
|
---|
90 | /***********************************************************************
|
---|
91 | * PCM_GetFormatIndex
|
---|
92 | */
|
---|
93 | static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
|
---|
94 | {
|
---|
95 | int i;
|
---|
96 |
|
---|
97 | for (i = 0; i < NUM_PCM_FORMATS; i++) {
|
---|
98 | if (wfx->nChannels == PCM_Formats[i].nChannels &&
|
---|
99 | wfx->nSamplesPerSec == PCM_Formats[i].rate &&
|
---|
100 | wfx->wBitsPerSample == PCM_Formats[i].nBits)
|
---|
101 | return i;
|
---|
102 | }
|
---|
103 | return 0xFFFFFFFF;
|
---|
104 | }
|
---|
105 |
|
---|
106 | /* PCM Conversions:
|
---|
107 | *
|
---|
108 | * parameters:
|
---|
109 | * + 8 bit unsigned vs 16 bit signed
|
---|
110 | * + mono vs stereo (1 or 2 channels)
|
---|
111 | * + sampling rate (8.0, 11.025, 22.05, 44.1 kHz are defined, but algo shall work
|
---|
112 | * in all cases)
|
---|
113 | *
|
---|
114 | * mono => stereo: copy the same sample on Left & Right channels
|
---|
115 | * stereo =) mono: use the average value of samples from Left & Right channels
|
---|
116 | * resampling; we lookup for each destination sample the two source adjacent samples
|
---|
117 | * were src <= dst < src+1 (dst is increased by a fractional value which is
|
---|
118 | * equivalent to the increment by one on src); then we use a linear
|
---|
119 | * interpolation between src and src+1
|
---|
120 | */
|
---|
121 |
|
---|
122 | /***********************************************************************
|
---|
123 | * C816
|
---|
124 | *
|
---|
125 | * Converts a 8 bit sample to a 16 bit one
|
---|
126 | */
|
---|
127 | static inline short C816(unsigned char b)
|
---|
128 | {
|
---|
129 | return (short)(b ^ 0x80) * 256;
|
---|
130 | }
|
---|
131 |
|
---|
132 | /***********************************************************************
|
---|
133 | * C168
|
---|
134 | *
|
---|
135 | * Converts a 16 bit sample to a 8 bit one (data loss !!)
|
---|
136 | */
|
---|
137 | static inline unsigned char C168(short s)
|
---|
138 | {
|
---|
139 | return HIBYTE(s) ^ (unsigned char)0x80;
|
---|
140 | }
|
---|
141 |
|
---|
142 | /***********************************************************************
|
---|
143 | * R16
|
---|
144 | *
|
---|
145 | * Read a 16 bit sample (correctly handles endianess)
|
---|
146 | */
|
---|
147 | static inline short R16(const unsigned char* src)
|
---|
148 | {
|
---|
149 | return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
|
---|
150 | }
|
---|
151 |
|
---|
152 | /***********************************************************************
|
---|
153 | * W16
|
---|
154 | *
|
---|
155 | * Write a 16 bit sample (correctly handles endianess)
|
---|
156 | */
|
---|
157 | static inline void W16(unsigned char* dst, short s)
|
---|
158 | {
|
---|
159 | dst[0] = LOBYTE(s);
|
---|
160 | dst[1] = HIBYTE(s);
|
---|
161 | }
|
---|
162 |
|
---|
163 | /***********************************************************************
|
---|
164 | * M16
|
---|
165 | *
|
---|
166 | * Convert the (l,r) 16 bit stereo sample into a 16 bit mono
|
---|
167 | * (takes the mid-point of the two values)
|
---|
168 | */
|
---|
169 | static inline short M16(short l, short r)
|
---|
170 | {
|
---|
171 | return (l + r) / 2;
|
---|
172 | }
|
---|
173 |
|
---|
174 | /***********************************************************************
|
---|
175 | * M8
|
---|
176 | *
|
---|
177 | * Convert the (l,r) 8 bit stereo sample into a 8 bit mono
|
---|
178 | * (takes the mid-point of the two values)
|
---|
179 | */
|
---|
180 | static inline unsigned char M8(unsigned char a, unsigned char b)
|
---|
181 | {
|
---|
182 | return (unsigned char)((a + b) / 2);
|
---|
183 | }
|
---|
184 |
|
---|
185 | /* the conversion routines without rate conversion are labelled cvt<X><Y><N><M>K
|
---|
186 | * where :
|
---|
187 | * <X> is the (M)ono/(S)tereo configuration of input channel
|
---|
188 | * <Y> is the (M)ono/(S)tereo configuration of output channel
|
---|
189 | * <N> is the number of bits of input channel (8 or 16)
|
---|
190 | * <M> is the number of bits of output channel (8 or 16)
|
---|
191 | *
|
---|
192 | * in the parameters, ns is always the number of samples, so the size of input
|
---|
193 | * buffer (resp output buffer) is ns * (<X> == 'Mono' ? 1:2) * (<N> == 8 ? 1:2)
|
---|
194 | */
|
---|
195 |
|
---|
196 | static void cvtMM88K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
197 | {
|
---|
198 | memcpy(dst, src, ns);
|
---|
199 | }
|
---|
200 |
|
---|
201 | static void cvtSS88K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
202 | {
|
---|
203 | memcpy(dst, src, ns * 2);
|
---|
204 | }
|
---|
205 |
|
---|
206 | static void cvtMM1616K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
207 | {
|
---|
208 | memcpy(dst, src, ns * 2);
|
---|
209 | }
|
---|
210 |
|
---|
211 | static void cvtSS1616K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
212 | {
|
---|
213 | memcpy(dst, src, ns * 4);
|
---|
214 | }
|
---|
215 |
|
---|
216 | static void cvtMS88K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
217 | {
|
---|
218 | while (ns--) {
|
---|
219 | *dst++ = *src;
|
---|
220 | *dst++ = *src++;
|
---|
221 | }
|
---|
222 | }
|
---|
223 |
|
---|
224 | static void cvtMS816K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
225 | {
|
---|
226 | short v;
|
---|
227 |
|
---|
228 | while (ns--) {
|
---|
229 | v = C816(*src++);
|
---|
230 | W16(dst, v); dst += 2;
|
---|
231 | W16(dst, v); dst += 2;
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 | static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
236 | {
|
---|
237 | unsigned char v;
|
---|
238 |
|
---|
239 | while (ns--) {
|
---|
240 | v = C168(R16(src)); src += 2;
|
---|
241 | *dst++ = v;
|
---|
242 | *dst++ = v;
|
---|
243 | }
|
---|
244 | }
|
---|
245 |
|
---|
246 | static void cvtMS1616K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
247 | {
|
---|
248 | short v;
|
---|
249 |
|
---|
250 | while (ns--) {
|
---|
251 | v = R16(src); src += 2;
|
---|
252 | W16(dst, v); dst += 2;
|
---|
253 | W16(dst, v); dst += 2;
|
---|
254 | }
|
---|
255 | }
|
---|
256 |
|
---|
257 | static void cvtSM88K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
258 | {
|
---|
259 | while (ns--) {
|
---|
260 | *dst++ = M8(src[0], src[1]);
|
---|
261 | src += 2;
|
---|
262 | }
|
---|
263 | }
|
---|
264 |
|
---|
265 | static void cvtSM816K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
266 | {
|
---|
267 | short v;
|
---|
268 |
|
---|
269 | while (ns--) {
|
---|
270 | v = M16(C816(src[0]), C816(src[1]));
|
---|
271 | src += 2;
|
---|
272 | W16(dst, v); dst += 2;
|
---|
273 | }
|
---|
274 | }
|
---|
275 |
|
---|
276 | static void cvtSM168K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
277 | {
|
---|
278 | while (ns--) {
|
---|
279 | *dst++ = C168(M16(R16(src), R16(src + 2)));
|
---|
280 | src += 4;
|
---|
281 | }
|
---|
282 | }
|
---|
283 |
|
---|
284 | static void cvtSM1616K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
285 | {
|
---|
286 | while (ns--) {
|
---|
287 | W16(dst, M16(R16(src),R16(src+2))); dst += 2;
|
---|
288 | src += 4;
|
---|
289 | }
|
---|
290 | }
|
---|
291 |
|
---|
292 | static void cvtMM816K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
293 | {
|
---|
294 | while (ns--) {
|
---|
295 | W16(dst, C816(*src++)); dst += 2;
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | static void cvtSS816K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
300 | {
|
---|
301 | while (ns--) {
|
---|
302 | W16(dst, C816(*src++)); dst += 2;
|
---|
303 | W16(dst, C816(*src++)); dst += 2;
|
---|
304 | }
|
---|
305 | }
|
---|
306 |
|
---|
307 | static void cvtMM168K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
308 | {
|
---|
309 | while (ns--) {
|
---|
310 | *dst++ = C168(R16(src)); src += 2;
|
---|
311 | }
|
---|
312 | }
|
---|
313 |
|
---|
314 | static void cvtSS168K(const unsigned char* src, int ns, unsigned char* dst)
|
---|
315 | {
|
---|
316 | while (ns--) {
|
---|
317 | *dst++ = C168(R16(src)); src += 2;
|
---|
318 | *dst++ = C168(R16(src)); src += 2;
|
---|
319 | }
|
---|
320 | }
|
---|
321 |
|
---|
322 | static void (*PCM_ConvertKeepRate[16])(const unsigned char*, int, unsigned char*) = {
|
---|
323 | cvtSS88K, cvtSM88K, cvtMS88K, cvtMM88K,
|
---|
324 | cvtSS816K, cvtSM816K, cvtMS816K, cvtMM816K,
|
---|
325 | cvtSS168K, cvtSM168K, cvtMS168K, cvtMM168K,
|
---|
326 | cvtSS1616K, cvtSM1616K, cvtMS1616K, cvtMM1616K,
|
---|
327 | };
|
---|
328 |
|
---|
329 | /***********************************************************************
|
---|
330 | * I
|
---|
331 | *
|
---|
332 | * Interpolate the value at r (r in ]0, 1]) between the two points v1 and v2
|
---|
333 | * Linear interpolation is used
|
---|
334 | */
|
---|
335 | static inline double I(double v1, double v2, double r)
|
---|
336 | {
|
---|
337 | if (0.0 >= r || r > 1.0) FIXME("r!! %f\n", r);
|
---|
338 | return (1.0 - r) * v1 + r * v2;
|
---|
339 | }
|
---|
340 |
|
---|
341 | static void cvtSS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
342 | unsigned char* dst, LPDWORD ndst)
|
---|
343 | {
|
---|
344 | double r;
|
---|
345 |
|
---|
346 | while (*nsrc != 0 && *ndst != 0) {
|
---|
347 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
348 | if (*nsrc == 0) return;
|
---|
349 | apd->last[0].b = *src++;
|
---|
350 | apd->last[1].b = *src++;
|
---|
351 | apd->srcPos++;
|
---|
352 | (*nsrc)--;
|
---|
353 | }
|
---|
354 | /* now do the interpolation */
|
---|
355 | *dst++ = I(apd->last[0].b, src[0], r);
|
---|
356 | *dst++ = I(apd->last[1].b, src[1], r);
|
---|
357 | apd->dstPos += apd->dstIncr;
|
---|
358 | (*ndst)--;
|
---|
359 | }
|
---|
360 | }
|
---|
361 |
|
---|
362 | /* the conversion routines with rate conversion are labelled cvt<X><Y><N><M>C
|
---|
363 | * where :
|
---|
364 | * <X> is the (M)ono/(S)tereo configuration of input channel
|
---|
365 | * <Y> is the (M)ono/(S)tereo configuration of output channel
|
---|
366 | * <N> is the number of bits of input channel (8 or 16)
|
---|
367 | * <M> is the number of bits of output channel (8 or 16)
|
---|
368 | *
|
---|
369 | */
|
---|
370 | static void cvtSM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
371 | unsigned char* dst, LPDWORD ndst)
|
---|
372 | {
|
---|
373 | double r;
|
---|
374 |
|
---|
375 | while (*nsrc != 0 && *ndst != 0) {
|
---|
376 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
377 | if (*nsrc == 0) return;
|
---|
378 | apd->last[0].b = *src++;
|
---|
379 | apd->last[1].b = *src++;
|
---|
380 | apd->srcPos++;
|
---|
381 | (*nsrc)--;
|
---|
382 | }
|
---|
383 | /* now do the interpolation */
|
---|
384 | *dst++ = I(M8(apd->last[0].b, apd->last[1].b), M8(src[0], src[1]), r);
|
---|
385 | apd->dstPos += apd->dstIncr;
|
---|
386 | (*ndst)--;
|
---|
387 | }
|
---|
388 | }
|
---|
389 |
|
---|
390 | static void cvtMS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
391 | unsigned char* dst, LPDWORD ndst)
|
---|
392 | {
|
---|
393 | double r;
|
---|
394 |
|
---|
395 | while (*nsrc != 0 && *ndst != 0) {
|
---|
396 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
397 | if (*nsrc == 0) return;
|
---|
398 | apd->last[0].b = *src++;
|
---|
399 | apd->srcPos++;
|
---|
400 | (*nsrc)--;
|
---|
401 | }
|
---|
402 | /* now do the interpolation */
|
---|
403 | dst[0] = dst[1] = I(apd->last[0].b, src[0], r);
|
---|
404 | dst += 2;
|
---|
405 | apd->dstPos += apd->dstIncr;
|
---|
406 | (*ndst)--;
|
---|
407 | }
|
---|
408 | }
|
---|
409 |
|
---|
410 | static void cvtMM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
411 | unsigned char* dst, LPDWORD ndst)
|
---|
412 | {
|
---|
413 | double r;
|
---|
414 |
|
---|
415 | while (*nsrc != 0 && *ndst != 0) {
|
---|
416 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
417 | if (*nsrc == 0) return;
|
---|
418 | apd->last[0].b = *src++;
|
---|
419 | apd->srcPos++;
|
---|
420 | (*nsrc)--;
|
---|
421 | }
|
---|
422 | /* now do the interpolation */
|
---|
423 | *dst++ = I(apd->last[0].b, src[0], r);
|
---|
424 | apd->dstPos += apd->dstIncr;
|
---|
425 | (*ndst)--;
|
---|
426 | }
|
---|
427 | }
|
---|
428 |
|
---|
429 | static void cvtSS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
430 | unsigned char* dst, LPDWORD ndst)
|
---|
431 | {
|
---|
432 | double r;
|
---|
433 |
|
---|
434 | while (*nsrc != 0 && *ndst != 0) {
|
---|
435 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
436 | if (*nsrc == 0) return;
|
---|
437 | apd->last[0].b = *src++;
|
---|
438 | apd->last[1].b = *src++;
|
---|
439 | apd->srcPos++;
|
---|
440 | (*nsrc)--;
|
---|
441 | }
|
---|
442 | /* now do the interpolation */
|
---|
443 | W16(dst, I(C816(apd->last[0].b), C816(src[0]), r)); dst += 2;
|
---|
444 | W16(dst, I(C816(apd->last[1].b), C816(src[1]), r)); dst += 2;
|
---|
445 | apd->dstPos += apd->dstIncr;
|
---|
446 | (*ndst)--;
|
---|
447 | }
|
---|
448 | }
|
---|
449 |
|
---|
450 | static void cvtSM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
451 | unsigned char* dst, LPDWORD ndst)
|
---|
452 | {
|
---|
453 | double r;
|
---|
454 |
|
---|
455 | while (*nsrc != 0 && *ndst != 0) {
|
---|
456 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
457 | if (*nsrc == 0) return;
|
---|
458 | apd->last[0].b = *src++;
|
---|
459 | apd->last[1].b = *src++;
|
---|
460 | apd->srcPos++;
|
---|
461 | (*nsrc)--;
|
---|
462 | }
|
---|
463 | /* now do the interpolation */
|
---|
464 | W16(dst, I(M16(C816(apd->last[0].b), C816(apd->last[1].b)),
|
---|
465 | M16(C816(src[0]), C816(src[1])), r));
|
---|
466 | dst += 2;
|
---|
467 | apd->dstPos += apd->dstIncr;
|
---|
468 | (*ndst)--;
|
---|
469 | }
|
---|
470 | }
|
---|
471 |
|
---|
472 | static void cvtMS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
473 | unsigned char* dst, LPDWORD ndst)
|
---|
474 | {
|
---|
475 | double r;
|
---|
476 | short v;
|
---|
477 |
|
---|
478 | while (*nsrc != 0 && *ndst != 0) {
|
---|
479 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
480 | if (*nsrc == 0) return;
|
---|
481 | apd->last[0].b = *src++;
|
---|
482 | apd->srcPos++;
|
---|
483 | (*nsrc)--;
|
---|
484 | }
|
---|
485 | /* now do the interpolation */
|
---|
486 | v = I(C816(apd->last[0].b), C816(src[0]), r);
|
---|
487 | W16(dst, v); dst += 2;
|
---|
488 | W16(dst, v); dst += 2;
|
---|
489 | apd->dstPos += apd->dstIncr;
|
---|
490 | (*ndst)--;
|
---|
491 | }
|
---|
492 | }
|
---|
493 |
|
---|
494 | static void cvtMM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
495 | unsigned char* dst, LPDWORD ndst)
|
---|
496 | {
|
---|
497 | double r;
|
---|
498 |
|
---|
499 | while (*nsrc != 0 && *ndst != 0) {
|
---|
500 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
501 | if (*nsrc == 0) return;
|
---|
502 | apd->last[0].b = *src++;
|
---|
503 | apd->srcPos++;
|
---|
504 | (*nsrc)--;
|
---|
505 | }
|
---|
506 | /* now do the interpolation */
|
---|
507 | W16(dst, I(C816(apd->last[0].b), C816(src[0]), r));
|
---|
508 | dst += 2;
|
---|
509 | apd->dstPos += apd->dstIncr;
|
---|
510 | (*ndst)--;
|
---|
511 | }
|
---|
512 | }
|
---|
513 |
|
---|
514 | static void cvtSS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
515 | unsigned char* dst, LPDWORD ndst)
|
---|
516 | {
|
---|
517 | double r;
|
---|
518 |
|
---|
519 | while (*nsrc != 0 && *ndst != 0) {
|
---|
520 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
521 | if (*nsrc == 0) return;
|
---|
522 | apd->last[0].s = R16(src); src += 2;
|
---|
523 | apd->last[1].s = R16(src); src += 2;
|
---|
524 | apd->srcPos++;
|
---|
525 | (*nsrc)--;
|
---|
526 | }
|
---|
527 | /* now do the interpolation */
|
---|
528 | *dst++ = C168(I(apd->last[0].s, R16(src) , r));
|
---|
529 | *dst++ = C168(I(apd->last[1].s, R16(src+2), r));
|
---|
530 | apd->dstPos += apd->dstIncr;
|
---|
531 | (*ndst)--;
|
---|
532 | }
|
---|
533 | }
|
---|
534 |
|
---|
535 | static void cvtSM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
536 | unsigned char* dst, LPDWORD ndst)
|
---|
537 | {
|
---|
538 | double r;
|
---|
539 |
|
---|
540 | while (*nsrc != 0 && *ndst != 0) {
|
---|
541 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
542 | if (*nsrc == 0) return;
|
---|
543 | apd->last[0].s = R16(src); src += 2;
|
---|
544 | apd->last[1].s = R16(src); src += 2;
|
---|
545 | apd->srcPos++;
|
---|
546 | (*nsrc)--;
|
---|
547 | }
|
---|
548 | /* now do the interpolation */
|
---|
549 | *dst++ = C168(I(M16(apd->last[0].s, apd->last[1].s),
|
---|
550 | M16(R16(src), R16(src + 2)), r));
|
---|
551 | apd->dstPos += apd->dstIncr;
|
---|
552 | (*ndst)--;
|
---|
553 | }
|
---|
554 | }
|
---|
555 |
|
---|
556 |
|
---|
557 | static void cvtMS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
558 | unsigned char* dst, LPDWORD ndst)
|
---|
559 | {
|
---|
560 | double r;
|
---|
561 |
|
---|
562 | while (*nsrc != 0 && *ndst != 0) {
|
---|
563 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
564 | if (*nsrc == 0) return;
|
---|
565 | apd->last[0].s = R16(src); src += 2;
|
---|
566 | apd->srcPos++;
|
---|
567 | (*nsrc)--;
|
---|
568 | }
|
---|
569 | /* now do the interpolation */
|
---|
570 | dst[0] = dst[1] = C168(I(apd->last[0].s, R16(src), r)); dst += 2;
|
---|
571 | apd->dstPos += apd->dstIncr;
|
---|
572 | (*ndst)--;
|
---|
573 | }
|
---|
574 | }
|
---|
575 |
|
---|
576 |
|
---|
577 | static void cvtMM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
578 | unsigned char* dst, LPDWORD ndst)
|
---|
579 | {
|
---|
580 | double r;
|
---|
581 |
|
---|
582 | while (*nsrc != 0 && *ndst != 0) {
|
---|
583 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
584 | if (*nsrc == 0) return;
|
---|
585 | apd->last[0].s = R16(src); src += 2;
|
---|
586 | apd->srcPos++;
|
---|
587 | (*nsrc)--;
|
---|
588 | }
|
---|
589 | /* now do the interpolation */
|
---|
590 | *dst++ = C168(I(apd->last[0].s, R16(src), r));
|
---|
591 | apd->dstPos += apd->dstIncr;
|
---|
592 | (*ndst)--;
|
---|
593 | }
|
---|
594 | }
|
---|
595 |
|
---|
596 | static void cvtSS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
597 | unsigned char* dst, LPDWORD ndst)
|
---|
598 | {
|
---|
599 | double r;
|
---|
600 |
|
---|
601 | while (*nsrc != 0 && *ndst != 0) {
|
---|
602 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
603 | if (*nsrc == 0) return;
|
---|
604 | apd->last[0].s = R16(src); src += 2;
|
---|
605 | apd->last[1].s = R16(src); src += 2;
|
---|
606 | apd->srcPos++;
|
---|
607 | (*nsrc)--;
|
---|
608 | }
|
---|
609 | /* now do the interpolation */
|
---|
610 | W16(dst, I(apd->last[0].s, R16(src) , r)); dst += 2;
|
---|
611 | W16(dst, I(apd->last[1].s, R16(src+2), r)); dst += 2;
|
---|
612 | apd->dstPos += apd->dstIncr;
|
---|
613 | (*ndst)--;
|
---|
614 | }
|
---|
615 | }
|
---|
616 |
|
---|
617 | static void cvtSM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
618 | unsigned char* dst, LPDWORD ndst)
|
---|
619 | {
|
---|
620 | double r;
|
---|
621 |
|
---|
622 | while (*nsrc != 0 && *ndst != 0) {
|
---|
623 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
624 | if (*nsrc == 0) return;
|
---|
625 | apd->last[0].s = R16(src); src += 2;
|
---|
626 | apd->last[1].s = R16(src); src += 2;
|
---|
627 | apd->srcPos++;
|
---|
628 | (*nsrc)--;
|
---|
629 | }
|
---|
630 | /* now do the interpolation */
|
---|
631 | W16(dst, I(M16(apd->last[0].s, apd->last[1].s),
|
---|
632 | M16(R16(src), R16(src+2)), r));
|
---|
633 | dst += 2;
|
---|
634 | apd->dstPos += apd->dstIncr;
|
---|
635 | (*ndst)--;
|
---|
636 | }
|
---|
637 | }
|
---|
638 |
|
---|
639 | static void cvtMS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
640 | unsigned char* dst, LPDWORD ndst)
|
---|
641 | {
|
---|
642 | double r;
|
---|
643 | short v;
|
---|
644 |
|
---|
645 | while (*nsrc != 0 && *ndst != 0) {
|
---|
646 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
647 | if (*nsrc == 0) return;
|
---|
648 | apd->last[0].s = R16(src); src += 2;
|
---|
649 | apd->srcPos++;
|
---|
650 | (*nsrc)--;
|
---|
651 | }
|
---|
652 | /* now do the interpolation */
|
---|
653 | v = I(apd->last[0].s, R16(src), r);
|
---|
654 | W16(dst, v); dst += 2;
|
---|
655 | W16(dst, v); dst += 2;
|
---|
656 | apd->dstPos += apd->dstIncr;
|
---|
657 | (*ndst)--;
|
---|
658 | }
|
---|
659 | }
|
---|
660 |
|
---|
661 | static void cvtMM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
---|
662 | unsigned char* dst, LPDWORD ndst)
|
---|
663 | {
|
---|
664 | double r;
|
---|
665 |
|
---|
666 | while (*nsrc != 0 && *ndst != 0) {
|
---|
667 | while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
|
---|
668 | if (*nsrc == 0) return;
|
---|
669 | apd->last[0].s = R16(src); src += 2;
|
---|
670 | apd->srcPos++;
|
---|
671 | (*nsrc)--;
|
---|
672 | }
|
---|
673 | /* now do the interpolation */
|
---|
674 | W16(dst, I(apd->last[0].s, R16(src), r)); dst += 2;
|
---|
675 | apd->dstPos += apd->dstIncr;
|
---|
676 | (*ndst)--;
|
---|
677 | }
|
---|
678 | }
|
---|
679 |
|
---|
680 | static void (*PCM_ConvertChangeRate[16])(AcmPcmData* apd,
|
---|
681 | const unsigned char* src, LPDWORD nsrc,
|
---|
682 | unsigned char* dst, LPDWORD ndst) = {
|
---|
683 | cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C,
|
---|
684 | cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C,
|
---|
685 | cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C,
|
---|
686 | cvtSS1616C, cvtSM1616C, cvtMS1616C, cvtMM1616C,
|
---|
687 | };
|
---|
688 |
|
---|
689 | /***********************************************************************
|
---|
690 | * PCM_DriverDetails
|
---|
691 | *
|
---|
692 | */
|
---|
693 | static LRESULT PCM_DriverDetails(PACMDRIVERDETAILSW add)
|
---|
694 | {
|
---|
695 | add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
|
---|
696 | add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
|
---|
697 | add->wMid = 0xFF;
|
---|
698 | add->wPid = 0x00;
|
---|
699 | add->vdwACM = 0x01000000;
|
---|
700 | add->vdwDriver = 0x01000000;
|
---|
701 | add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
|
---|
702 | add->cFormatTags = 1;
|
---|
703 | add->cFilterTags = 0;
|
---|
704 | add->hicon = (HICON)0;
|
---|
705 | MultiByteToWideChar( CP_ACP, 0, "WINE-PCM", -1,
|
---|
706 | add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
|
---|
707 | MultiByteToWideChar( CP_ACP, 0, "Wine PCM converter", -1,
|
---|
708 | add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
|
---|
709 | MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
|
---|
710 | add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
|
---|
711 | MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
|
---|
712 | add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
|
---|
713 | add->szFeatures[0] = 0;
|
---|
714 |
|
---|
715 | return MMSYSERR_NOERROR;
|
---|
716 | }
|
---|
717 |
|
---|
718 | /***********************************************************************
|
---|
719 | * PCM_FormatTagDetails
|
---|
720 | *
|
---|
721 | */
|
---|
722 | static LRESULT PCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
|
---|
723 | {
|
---|
724 | switch (dwQuery) {
|
---|
725 | case ACM_FORMATTAGDETAILSF_INDEX:
|
---|
726 | if (aftd->dwFormatTagIndex != 0) return ACMERR_NOTPOSSIBLE;
|
---|
727 | break;
|
---|
728 | case ACM_FORMATTAGDETAILSF_FORMATTAG:
|
---|
729 | if (aftd->dwFormatTag != WAVE_FORMAT_PCM) return ACMERR_NOTPOSSIBLE;
|
---|
730 | break;
|
---|
731 | case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
|
---|
732 | if (aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN &&
|
---|
733 | aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN)
|
---|
734 | return ACMERR_NOTPOSSIBLE;
|
---|
735 | break;
|
---|
736 | default:
|
---|
737 | WARN("Unsupported query %08lx\n", dwQuery);
|
---|
738 | return MMSYSERR_NOTSUPPORTED;
|
---|
739 | }
|
---|
740 |
|
---|
741 | aftd->dwFormatTagIndex = 0;
|
---|
742 | aftd->dwFormatTag = WAVE_FORMAT_PCM;
|
---|
743 | aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
|
---|
744 | aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
|
---|
745 | aftd->cStandardFormats = NUM_PCM_FORMATS;
|
---|
746 | aftd->szFormatTag[0] = 0;
|
---|
747 |
|
---|
748 | return MMSYSERR_NOERROR;
|
---|
749 | }
|
---|
750 |
|
---|
751 | /***********************************************************************
|
---|
752 | * PCM_FormatDetails
|
---|
753 | *
|
---|
754 | */
|
---|
755 | static LRESULT PCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
|
---|
756 | {
|
---|
757 | switch (dwQuery) {
|
---|
758 | case ACM_FORMATDETAILSF_FORMAT:
|
---|
759 | afd->dwFormatIndex = PCM_GetFormatIndex(afd->pwfx);
|
---|
760 | if (afd->dwFormatIndex == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
|
---|
761 | break;
|
---|
762 | case ACM_FORMATDETAILSF_INDEX:
|
---|
763 | assert(afd->dwFormatIndex < NUM_PCM_FORMATS);
|
---|
764 | afd->pwfx->wFormatTag = WAVE_FORMAT_PCM;
|
---|
765 | afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
|
---|
766 | afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
|
---|
767 | afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
|
---|
768 | /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
|
---|
769 | * afd->pwfx->cbSize = 0;
|
---|
770 | */
|
---|
771 | afd->pwfx->nBlockAlign =
|
---|
772 | (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
|
---|
773 | afd->pwfx->nAvgBytesPerSec =
|
---|
774 | afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
|
---|
775 | break;
|
---|
776 | default:
|
---|
777 | WARN("Unsupported query %08lx\n", dwQuery);
|
---|
778 | return MMSYSERR_NOTSUPPORTED;
|
---|
779 | }
|
---|
780 |
|
---|
781 | afd->dwFormatTag = WAVE_FORMAT_PCM;
|
---|
782 | afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
|
---|
783 | afd->szFormat[0] = 0; /* let MSACM format this for us... */
|
---|
784 |
|
---|
785 | return MMSYSERR_NOERROR;
|
---|
786 | }
|
---|
787 |
|
---|
788 | /***********************************************************************
|
---|
789 | * PCM_FormatSuggest
|
---|
790 | *
|
---|
791 | */
|
---|
792 | static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
|
---|
793 | {
|
---|
794 | FIXME("(%p);\n", adfs);
|
---|
795 | return MMSYSERR_NOTSUPPORTED;
|
---|
796 | }
|
---|
797 |
|
---|
798 | /***********************************************************************
|
---|
799 | * PCM_Reset
|
---|
800 | *
|
---|
801 | */
|
---|
802 | static void PCM_Reset(AcmPcmData* apd, int srcNumBits)
|
---|
803 | {
|
---|
804 | apd->srcPos = 0;
|
---|
805 | apd->dstPos = 0;
|
---|
806 | /* initialize with neutral value */
|
---|
807 | if (srcNumBits == 16) {
|
---|
808 | apd->last[0].s = 0;
|
---|
809 | apd->last[1].s = 0;
|
---|
810 | } else {
|
---|
811 | apd->last[0].b = (BYTE)0x80;
|
---|
812 | apd->last[1].b = (BYTE)0x80;
|
---|
813 | }
|
---|
814 | }
|
---|
815 |
|
---|
816 | /***********************************************************************
|
---|
817 | * PCM_StreamOpen
|
---|
818 | *
|
---|
819 | */
|
---|
820 | static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
|
---|
821 | {
|
---|
822 | AcmPcmData* apd;
|
---|
823 | int idx = 0;
|
---|
824 |
|
---|
825 | assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
|
---|
826 |
|
---|
827 | if (PCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
|
---|
828 | PCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
|
---|
829 | return ACMERR_NOTPOSSIBLE;
|
---|
830 |
|
---|
831 | apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData));
|
---|
832 | if (apd == 0) return MMSYSERR_NOMEM;
|
---|
833 |
|
---|
834 | adsi->dwDriver = (DWORD)apd;
|
---|
835 | adsi->fdwDriver = 0;
|
---|
836 |
|
---|
837 | if (adsi->pwfxSrc->wBitsPerSample == 16) idx += 8;
|
---|
838 | if (adsi->pwfxDst->wBitsPerSample == 16) idx += 4;
|
---|
839 | if (adsi->pwfxSrc->nChannels == 1) idx += 2;
|
---|
840 | if (adsi->pwfxDst->nChannels == 1) idx += 1;
|
---|
841 |
|
---|
842 | if (adsi->pwfxSrc->nSamplesPerSec == adsi->pwfxDst->nSamplesPerSec) {
|
---|
843 | apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx];
|
---|
844 | } else {
|
---|
845 | adsi->fdwDriver |= PCM_RESAMPLE;
|
---|
846 | apd->dstIncr = (double)(adsi->pwfxSrc->nSamplesPerSec) /
|
---|
847 | (double)(adsi->pwfxDst->nSamplesPerSec);
|
---|
848 | PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample);
|
---|
849 | apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx];
|
---|
850 | }
|
---|
851 |
|
---|
852 | return MMSYSERR_NOERROR;
|
---|
853 | }
|
---|
854 |
|
---|
855 | /***********************************************************************
|
---|
856 | * PCM_StreamClose
|
---|
857 | *
|
---|
858 | */
|
---|
859 | static LRESULT PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
|
---|
860 | {
|
---|
861 | HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
|
---|
862 | return MMSYSERR_NOERROR;
|
---|
863 | }
|
---|
864 |
|
---|
865 | /***********************************************************************
|
---|
866 | * PCM_round
|
---|
867 | *
|
---|
868 | */
|
---|
869 | static inline DWORD PCM_round(DWORD a, DWORD b, DWORD c)
|
---|
870 | {
|
---|
871 | assert(a && b && c);
|
---|
872 | /* to be sure, always return an entire number of c... */
|
---|
873 | return ((double)a * (double)b + (double)c - 1) / (double)c;
|
---|
874 | }
|
---|
875 |
|
---|
876 | /***********************************************************************
|
---|
877 | * PCM_StreamSize
|
---|
878 | *
|
---|
879 | */
|
---|
880 | static LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
|
---|
881 | {
|
---|
882 | switch (adss->fdwSize) {
|
---|
883 | case ACM_STREAMSIZEF_DESTINATION:
|
---|
884 | /* cbDstLength => cbSrcLength */
|
---|
885 | adss->cbSrcLength = PCM_round(adss->cbDstLength,
|
---|
886 | adsi->pwfxSrc->nAvgBytesPerSec,
|
---|
887 | adsi->pwfxDst->nAvgBytesPerSec);
|
---|
888 | break;
|
---|
889 | case ACM_STREAMSIZEF_SOURCE:
|
---|
890 | /* cbSrcLength => cbDstLength */
|
---|
891 | adss->cbDstLength = PCM_round(adss->cbSrcLength,
|
---|
892 | adsi->pwfxDst->nAvgBytesPerSec,
|
---|
893 | adsi->pwfxSrc->nAvgBytesPerSec);
|
---|
894 | break;
|
---|
895 | default:
|
---|
896 | WARN("Unsupported query %08lx\n", adss->fdwSize);
|
---|
897 | return MMSYSERR_NOTSUPPORTED;
|
---|
898 | }
|
---|
899 | return MMSYSERR_NOERROR;
|
---|
900 | }
|
---|
901 |
|
---|
902 | /***********************************************************************
|
---|
903 | * PCM_StreamConvert
|
---|
904 | *
|
---|
905 | */
|
---|
906 | static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
|
---|
907 | {
|
---|
908 | AcmPcmData* apd = (AcmPcmData*)adsi->dwDriver;
|
---|
909 | DWORD nsrc = NUM_OF(adsh->cbSrcLength, adsi->pwfxSrc->nBlockAlign);
|
---|
910 | DWORD ndst = NUM_OF(adsh->cbDstLength, adsi->pwfxDst->nBlockAlign);
|
---|
911 |
|
---|
912 | if (adsh->fdwConvert &
|
---|
913 | ~(ACM_STREAMCONVERTF_BLOCKALIGN|
|
---|
914 | ACM_STREAMCONVERTF_END|
|
---|
915 | ACM_STREAMCONVERTF_START)) {
|
---|
916 | FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
|
---|
917 | }
|
---|
918 | /* ACM_STREAMCONVERTF_BLOCKALIGN
|
---|
919 | * currently all conversions are block aligned, so do nothing for this flag
|
---|
920 | * ACM_STREAMCONVERTF_END
|
---|
921 | * no pending data, so do nothing for this flag
|
---|
922 | */
|
---|
923 | if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) &&
|
---|
924 | (adsi->fdwDriver & PCM_RESAMPLE)) {
|
---|
925 | PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample);
|
---|
926 | }
|
---|
927 |
|
---|
928 | /* do the job */
|
---|
929 | if (adsi->fdwDriver & PCM_RESAMPLE) {
|
---|
930 | DWORD nsrc2 = nsrc;
|
---|
931 | DWORD ndst2 = ndst;
|
---|
932 |
|
---|
933 | apd->cvt.cvtChangeRate(apd, adsh->pbSrc, &nsrc2, adsh->pbDst, &ndst2);
|
---|
934 | nsrc -= nsrc2;
|
---|
935 | ndst -= ndst2;
|
---|
936 | } else {
|
---|
937 | if (nsrc < ndst) ndst = nsrc; else nsrc = ndst;
|
---|
938 |
|
---|
939 | /* nsrc is now equal to ndst */
|
---|
940 | apd->cvt.cvtKeepRate(adsh->pbSrc, nsrc, adsh->pbDst);
|
---|
941 | }
|
---|
942 |
|
---|
943 | adsh->cbSrcLengthUsed = nsrc * adsi->pwfxSrc->nBlockAlign;
|
---|
944 | adsh->cbDstLengthUsed = ndst * adsi->pwfxDst->nBlockAlign;
|
---|
945 |
|
---|
946 | return MMSYSERR_NOERROR;
|
---|
947 | }
|
---|
948 |
|
---|
949 | /**************************************************************************
|
---|
950 | * PCM_DriverProc [exported]
|
---|
951 | */
|
---|
952 | LRESULT CALLBACK PCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg,
|
---|
953 | LPARAM dwParam1, LPARAM dwParam2)
|
---|
954 | {
|
---|
955 | TRACE("(%08lx %08lx %u %08lx %08lx);\n",
|
---|
956 | dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2);
|
---|
957 |
|
---|
958 | switch (wMsg) {
|
---|
959 | case DRV_LOAD: return 1;
|
---|
960 | case DRV_FREE: return 1;
|
---|
961 | case DRV_OPEN: return PCM_drvOpen((LPSTR)dwParam1);
|
---|
962 | case DRV_CLOSE: return PCM_drvClose(dwDevID);
|
---|
963 | case DRV_ENABLE: return 1;
|
---|
964 | case DRV_DISABLE: return 1;
|
---|
965 | case DRV_QUERYCONFIGURE: return 1;
|
---|
966 | case DRV_CONFIGURE: MessageBoxA(0, "MSACM PCM filter !", "Wine Driver", MB_OK); return 1;
|
---|
967 | case DRV_INSTALL: return DRVCNF_RESTART;
|
---|
968 | case DRV_REMOVE: return DRVCNF_RESTART;
|
---|
969 |
|
---|
970 | case ACMDM_DRIVER_NOTIFY:
|
---|
971 | /* no caching from other ACM drivers is done so far */
|
---|
972 | return MMSYSERR_NOERROR;
|
---|
973 |
|
---|
974 | case ACMDM_DRIVER_DETAILS:
|
---|
975 | return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
|
---|
976 |
|
---|
977 | case ACMDM_FORMATTAG_DETAILS:
|
---|
978 | return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
|
---|
979 |
|
---|
980 | case ACMDM_FORMAT_DETAILS:
|
---|
981 | return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
|
---|
982 |
|
---|
983 | case ACMDM_FORMAT_SUGGEST:
|
---|
984 | return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
|
---|
985 |
|
---|
986 | case ACMDM_STREAM_OPEN:
|
---|
987 | return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
|
---|
988 |
|
---|
989 | case ACMDM_STREAM_CLOSE:
|
---|
990 | return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
|
---|
991 |
|
---|
992 | case ACMDM_STREAM_SIZE:
|
---|
993 | return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
|
---|
994 |
|
---|
995 | case ACMDM_STREAM_CONVERT:
|
---|
996 | return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
|
---|
997 |
|
---|
998 | case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
|
---|
999 | case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
|
---|
1000 | /* this converter is not a hardware driver */
|
---|
1001 | case ACMDM_FILTERTAG_DETAILS:
|
---|
1002 | case ACMDM_FILTER_DETAILS:
|
---|
1003 | /* this converter is not a filter */
|
---|
1004 | case ACMDM_STREAM_RESET:
|
---|
1005 | /* only needed for asynchronous driver... we aren't, so just say it */
|
---|
1006 | case ACMDM_STREAM_PREPARE:
|
---|
1007 | case ACMDM_STREAM_UNPREPARE:
|
---|
1008 | /* nothing special to do here... so don't do anything */
|
---|
1009 | return MMSYSERR_NOTSUPPORTED;
|
---|
1010 |
|
---|
1011 | default:
|
---|
1012 | return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
|
---|
1013 | }
|
---|
1014 | return 0;
|
---|
1015 | }
|
---|