1 | /* $Id: waudio.cpp 561 2011-07-28 09:16:56Z rudi $ */
|
---|
2 |
|
---|
3 | /* SCCSID = %W% %E% */
|
---|
4 | /****************************************************************************
|
---|
5 | * *
|
---|
6 | * Copyright (c) IBM Corporation 1994 - 1997. *
|
---|
7 | * *
|
---|
8 | * The following IBM OS/2 source code is provided to you solely for the *
|
---|
9 | * the purpose of assisting you in your development of OS/2 device drivers. *
|
---|
10 | * You may use this code in accordance with the IBM License Agreement *
|
---|
11 | * provided in the IBM Device Driver Source Kit for OS/2. *
|
---|
12 | * *
|
---|
13 | ****************************************************************************/
|
---|
14 | /**@internal %W%
|
---|
15 | * @notes
|
---|
16 | * @version %I%
|
---|
17 | * @context Unless otherwise noted, all interfaces are Ring-0, 16-bit,
|
---|
18 | * <stack context>.
|
---|
19 | * @history
|
---|
20 | *
|
---|
21 | */
|
---|
22 | #define INCL_NOPMAPI
|
---|
23 | #include <os2.h>
|
---|
24 | #include <os2medef.h>
|
---|
25 | #include <audio.h>
|
---|
26 |
|
---|
27 | #include "waudio.hpp"
|
---|
28 |
|
---|
29 |
|
---|
30 | //
|
---|
31 | //
|
---|
32 | // the following 3-D array defines the subtypes for DATATYPE_WAVEFORM
|
---|
33 | // The array is 4x2x2 and is indexed using frequency index, bits per
|
---|
34 | // sample being 8 or 16 represented by 0 or 1 resp. and mono or stereo
|
---|
35 | // mode represented by 0 or 1 respectively. For eg. to find out the
|
---|
36 | // subtype for 22050Hz sampling frequency, using 16 bits per sample
|
---|
37 | // and stereo mode, we use aaulWave[FREQ22KHZ][BPS16][1]. This avoids
|
---|
38 | // inefficient nested if's and switches to find a matching value given
|
---|
39 | // the same.
|
---|
40 | //
|
---|
41 | ULONG aaulWave[NUMFREQS][BPSTYPES][MONOSTEREO] = {
|
---|
42 | WAVE_FORMAT_1M08, /* 11.025kHz, 8-bit Mono */
|
---|
43 | WAVE_FORMAT_1S08, /* 11.025kHz, 8-bit Stereo */
|
---|
44 | WAVE_FORMAT_1M16, /* 11.025kHz, 16-bit Mono */
|
---|
45 | WAVE_FORMAT_1S16, /* 11.025kHz, 16-bit Stereo */
|
---|
46 | WAVE_FORMAT_2M08, /* 22.05kHz , 8-bit Mono */
|
---|
47 | WAVE_FORMAT_2S08, /* 22.05kHz , 8-bit Stereo */
|
---|
48 | WAVE_FORMAT_2M16, /* 22.05kHz , 16-bit Mono */
|
---|
49 | WAVE_FORMAT_2S16, /* 22.05kHz , 16-bit Stereo */
|
---|
50 | WAVE_FORMAT_4M08, /* 44.1kHz , 8-bit Mono */
|
---|
51 | WAVE_FORMAT_4S08, /* 44.1kHz , 8-bit Stereo */
|
---|
52 | WAVE_FORMAT_4M16, /* 44.1kHz , 16-bit Mono */
|
---|
53 | WAVE_FORMAT_4S16, /* 44.1kHz , 16-bit Stereo */
|
---|
54 | WAVE_FORMAT_8M08, /* 8.0kHz , 8-bit Mono */
|
---|
55 | WAVE_FORMAT_8S08, /* 8.0kHz , 8-bit Stereo */
|
---|
56 | WAVE_FORMAT_8M16, /* 8.0kHz , 16-bit Mono */
|
---|
57 | WAVE_FORMAT_8S16 /* 8.0kHz , 16-bit Stereo */
|
---|
58 | };
|
---|
59 |
|
---|
60 | //
|
---|
61 | // the following 2-D array defines the subtypes for DATATYPE_ALAW
|
---|
62 | // it is indexed by the sampling rate ordinal (from
|
---|
63 | // _usfind_matching_sample_rate) and the number of channels
|
---|
64 | ULONG aaulAlaw[NUMFREQS][MONOSTEREO] = {
|
---|
65 | ALAW_8B11KM, /* 8bit 11kHz mono*/
|
---|
66 | ALAW_8B11KS, /* 8bit 11kHz stereo*/
|
---|
67 | ALAW_8B22KM, /* 8bit 22kHz mono*/
|
---|
68 | ALAW_8B22KS, /* 8bit 22kHz stereo*/
|
---|
69 | ALAW_8B44KM, /* 8bit 44kHz mono*/
|
---|
70 | ALAW_8B44KS, /* 8bit 44kHz stereo*/
|
---|
71 | ALAW_8B8KM , /* 8bit 8kHz mono*/
|
---|
72 | ALAW_8B8KS /* 8bit 8kHz stereo*/
|
---|
73 | };
|
---|
74 | //
|
---|
75 | // the following 2-D array defines the subtypes for DATATYPE_MULAW
|
---|
76 | // it is indexed by the sampling rate ordinal (from
|
---|
77 | // _usfind_matching_sample_rate) and the number of channels
|
---|
78 | ULONG aaulMulaw[NUMFREQS][MONOSTEREO] = {
|
---|
79 | MULAW_8B11KM, /* 8bit 11kHz mono*/
|
---|
80 | MULAW_8B11KS, /* 8bit 11kHz stereo*/
|
---|
81 | MULAW_8B22KM, /* 8bit 22kHz mono*/
|
---|
82 | MULAW_8B22KS, /* 8bit 22kHz stereo*/
|
---|
83 | MULAW_8B44KM, /* 8bit 44kHz mono*/
|
---|
84 | MULAW_8B44KS, /* 8bit 44kHz stereo*/
|
---|
85 | MULAW_8B8KM , /* 8bit 8kHz mono*/
|
---|
86 | MULAW_8B8KS /* 8bit 8kHz stereo*/
|
---|
87 | };
|
---|
88 |
|
---|
89 | //
|
---|
90 | // The aulSuppSampleRates array is used by member function
|
---|
91 | // _usfind_matching_sample_rate to determine the sampling rate
|
---|
92 | // ordinal
|
---|
93 | ULONG aulSuppSampleRates[] = {11025, 22050, 44100, 8000};
|
---|
94 |
|
---|
95 | // the following macro only takes positive arguments and returns the
|
---|
96 | // absolute difference between the two arguments
|
---|
97 | #define distance(x, y) ((x>y)? x-y : y-x)
|
---|
98 |
|
---|
99 | /**@internal _usfind_matching_sample_rate
|
---|
100 | * @param PULONG pulSampleRate
|
---|
101 | * @return
|
---|
102 | * @notes
|
---|
103 | * The following function takes a sampling rate as input and finds out
|
---|
104 | * the closest sampling rate in 11KHz, 22KHz, 44KHz and 8KHz. It retuns
|
---|
105 | * the ordinal value of the matching sampling rate which should be used
|
---|
106 | * to reference an array element by the frequency index.
|
---|
107 | * This function is called by the DevCaps member function.
|
---|
108 | *
|
---|
109 | */
|
---|
110 | USHORT WAVEAUDIO::_usfind_matching_sample_rate(PULONG pulSampleRate)
|
---|
111 | {
|
---|
112 | ULONG ulMinDistance = 0x7fffffff;
|
---|
113 | USHORT usMatching;
|
---|
114 | USHORT us;
|
---|
115 |
|
---|
116 | for ( us = 0; us < 4; us++ ) {
|
---|
117 | ULONG ulDistance = distance( *pulSampleRate, aulSuppSampleRates[us] );
|
---|
118 | if (ulDistance < ulMinDistance) {
|
---|
119 | ulMinDistance = ulDistance;
|
---|
120 | usMatching = us;
|
---|
121 | }
|
---|
122 | }
|
---|
123 | *pulSampleRate = aulSuppSampleRates[usMatching];
|
---|
124 | return usMatching;
|
---|
125 | }
|
---|
126 |
|
---|
127 | /**@internal
|
---|
128 | * @param
|
---|
129 | * @return
|
---|
130 | * @notes
|
---|
131 | *
|
---|
132 | */
|
---|
133 | void WAVEAUDIO::DevCaps(PAUDIO_CAPS pCaps)
|
---|
134 | {
|
---|
135 | USHORT usSampleRateIndex;
|
---|
136 | ULONG ulSampleRate;
|
---|
137 |
|
---|
138 |
|
---|
139 | // This device driver supports Playback or Record Operations
|
---|
140 | // anything else makes no sence. Note: This a per stream operation so
|
---|
141 | // even if this sevice can do full-duplex, it can not do PLAY_AND_RECORD
|
---|
142 |
|
---|
143 | if ( pCaps->ulOperation != OPERATION_PLAY &&
|
---|
144 | pCaps->ulOperation != OPERATION_RECORD ) {
|
---|
145 | pCaps->ulSupport = UNSUPPORTED_OPERATION;
|
---|
146 | return;
|
---|
147 | }
|
---|
148 |
|
---|
149 | // Stereo or Mono only
|
---|
150 | if (pCaps->ulChannels != 1 && pCaps->ulChannels != 2) {
|
---|
151 | pCaps->ulSupport = UNSUPPORTED_CHANNELS;
|
---|
152 | return;
|
---|
153 | }
|
---|
154 |
|
---|
155 | // supported bits per sample are 8 (for unsigned PCM, u-law or A-law )
|
---|
156 | // and 16 (for 2's complement PCM)
|
---|
157 | if (pCaps->ulBitsPerSample != 8 && pCaps->ulBitsPerSample != 16) {
|
---|
158 | pCaps->ulSupport = UNSUPPORTED_BPS;
|
---|
159 | return;
|
---|
160 | }
|
---|
161 |
|
---|
162 | ulSampleRate = pCaps->ulSamplingRate; //save the sampling rate called with
|
---|
163 |
|
---|
164 | // find out the closest sampling rate (may or may not be the same )
|
---|
165 | // from one of the following: 11025Hz, 22050Hz, 44100Hz and 8000Hz
|
---|
166 | // _usfind_matching_sample_rate will update pCaps->ulSamplingRate if there
|
---|
167 | // is not an exact match.
|
---|
168 | usSampleRateIndex = _usfind_matching_sample_rate(&pCaps->ulSamplingRate);
|
---|
169 |
|
---|
170 | // If _usfind_matching_sample_rate changed the sampling rate set
|
---|
171 | // the best fit flag.
|
---|
172 | if (ulSampleRate != pCaps->ulSamplingRate)
|
---|
173 | pCaps->ulFlags |= BESTFIT_PROVIDED;
|
---|
174 |
|
---|
175 | // Determine the ulDataSubType and update any format specific flags
|
---|
176 | // Note: All data types have more than one value.
|
---|
177 | switch ( pCaps->ulDataType ) {
|
---|
178 | case DATATYPE_WAVEFORM:
|
---|
179 | case PCM:
|
---|
180 | // determine subtype for PCM:
|
---|
181 | pCaps->ulDataSubType = aaulWave[usSampleRateIndex]
|
---|
182 | [(pCaps->ulBitsPerSample-8)/8]
|
---|
183 | [pCaps->ulChannels-1];
|
---|
184 | if (pCaps->ulBitsPerSample == 16)
|
---|
185 | pCaps->ulFlags |= TWOS_COMPLEMENT; // 2's complement data
|
---|
186 | break;
|
---|
187 |
|
---|
188 | #if 0
|
---|
189 | //SvL: Does the SB live hardware support this or is it just a limitation of the linux driver?
|
---|
190 | case DATATYPE_ALAW:
|
---|
191 | case DATATYPE_RIFF_ALAW:
|
---|
192 | case A_LAW:
|
---|
193 | // determine subtype for A_LAW
|
---|
194 | pCaps->ulDataSubType = aaulAlaw[usSampleRateIndex][pCaps->ulChannels-1];
|
---|
195 | break;
|
---|
196 |
|
---|
197 | case DATATYPE_MULAW:
|
---|
198 | case DATATYPE_RIFF_MULAW:
|
---|
199 | case MU_LAW:
|
---|
200 | // determine subtype for MU_LAW
|
---|
201 | pCaps->ulDataSubType = aaulMulaw[usSampleRateIndex][pCaps->ulChannels-1];
|
---|
202 | break;
|
---|
203 | #endif
|
---|
204 | default:
|
---|
205 | pCaps->ulSupport = UNSUPPORTED_DATATYPE;
|
---|
206 | return;
|
---|
207 | } // end switch
|
---|
208 |
|
---|
209 | pCaps->ulFlags = FIXED | // Fixed length data
|
---|
210 | LEFT_ALIGNED | // Left align bits on byte bndry
|
---|
211 | BIG_ENDIAN | // MSB's first (motorola format)
|
---|
212 | INPUT | // Input select is supported
|
---|
213 | OUTPUT | // Output select is supported
|
---|
214 | MONITOR | // Monitor is supported
|
---|
215 | VOLUME; // Volume control is supported
|
---|
216 |
|
---|
217 | // Full Duplex Enabling Stuff here !!
|
---|
218 | // The number of resource units is described in the MMPM2.INI
|
---|
219 | // This can be thought of the number of active streams the
|
---|
220 | // driver can manage at one time. We list this number as 2.
|
---|
221 | // we tell MMPM here how many of these units THIS stream will consume.
|
---|
222 | // The answer is so simple it's brilliant, (Thanks to Joe Nord at Crystal
|
---|
223 | // Semi) If we are enabled to do full-duplex this stream will consume 1
|
---|
224 | // unit, If we are not enabled to do full-duplex this stream will consume 2
|
---|
225 | // (or all the available units)
|
---|
226 | // Along with the resource units, we defined 2 resources classes,
|
---|
227 | // one for playback and one for capture. We tell MMPM (in the MMPM2.INI)
|
---|
228 | // that we can handle doing 1 playback and 1 capture stream or 1 capture and
|
---|
229 | // one playback stream at the same time. (Valid Resource combos in the
|
---|
230 | // MMPM2.INI) check if we are a playback or capture and set the correct
|
---|
231 | // resource class (Playback = 1, Capture = 2)
|
---|
232 |
|
---|
233 | pCaps->ulResourceUnits = 1;
|
---|
234 |
|
---|
235 | if ( pCaps->ulOperation == OPERATION_PLAY)
|
---|
236 | pCaps->ulResourceClass = 1;
|
---|
237 | else
|
---|
238 | pCaps->ulResourceClass = 2;
|
---|
239 | pCaps->fCanRecord = 1; // Yes Virgina we can record
|
---|
240 | pCaps->ulBlockAlign = 1; // Block alignment for this mode
|
---|
241 |
|
---|
242 | //return success
|
---|
243 | pCaps->ulSupport = SUPPORT_SUCCESS;
|
---|
244 |
|
---|
245 | }
|
---|
246 | /**@internal
|
---|
247 | * @param
|
---|
248 | * @return
|
---|
249 | * @notes
|
---|
250 | *
|
---|
251 | */
|
---|
252 | void WAVEAUDIO::DevCaps(LPDAUDIO_CAPS lpCaps)
|
---|
253 | {
|
---|
254 | lpCaps->dwFlags = DAUDIOCAPS_PRIMARYMONO |
|
---|
255 | DAUDIOCAPS_PRIMARYSTEREO |
|
---|
256 | DAUDIOCAPS_PRIMARY8BIT |
|
---|
257 | DAUDIOCAPS_PRIMARY16BIT |
|
---|
258 | DAUDIOCAPS_CONTINUOUSRATE |
|
---|
259 | DAUDIOCAPS_CERTIFIED |
|
---|
260 | DAUDIOCAPS_SECONDARYMONO |
|
---|
261 | DAUDIOCAPS_SECONDARYSTEREO |
|
---|
262 | DAUDIOCAPS_SECONDARY8BIT |
|
---|
263 | DAUDIOCAPS_SECONDARY16BIT;
|
---|
264 |
|
---|
265 | lpCaps->dwMinSecondarySampleRate = SBLIVECAPS_MINSAMPLERATE;
|
---|
266 | lpCaps->dwMaxSecondarySampleRate = SBLIVECAPS_MAXSAMPLERATE;
|
---|
267 | lpCaps->dwPrimaryBuffers = 1;
|
---|
268 | lpCaps->dwMaxHwMixingAllBuffers = SBLIVECAPS_MAXSTREAMS;
|
---|
269 | lpCaps->dwMaxHwMixingStaticBuffers = SBLIVECAPS_MAXSTREAMS;
|
---|
270 | lpCaps->dwMaxHwMixingStreamingBuffers = SBLIVECAPS_MAXSTREAMS;
|
---|
271 | lpCaps->dwMaxHw3DAllBuffers = 0;
|
---|
272 | lpCaps->dwMaxHw3DStaticBuffers = 0;
|
---|
273 | lpCaps->dwMaxHw3DStreamingBuffers = 0;
|
---|
274 | lpCaps->dwFreeHw3DAllBuffers = 0;
|
---|
275 | lpCaps->dwFreeHw3DStaticBuffers = 0;
|
---|
276 | lpCaps->dwFreeHw3DStreamingBuffers = 0;
|
---|
277 | lpCaps->dwTotalHwMemBytes = 0;
|
---|
278 | lpCaps->dwFreeHwMemBytes = 0;
|
---|
279 | lpCaps->dwMaxContigFreeHwMemBytes = 0;
|
---|
280 | lpCaps->dwUnlockTransferRateHwBuffers = 0;
|
---|
281 | lpCaps->dwPlayCpuOverheadSwBuffers = 0;
|
---|
282 | lpCaps->dwReserved1 = 0;
|
---|
283 | lpCaps->dwReserved2 = 0;
|
---|
284 | }
|
---|
285 |
|
---|
286 | /**@internal
|
---|
287 | * @param
|
---|
288 | * @return
|
---|
289 | * @notes
|
---|
290 | *
|
---|
291 | */
|
---|
292 | #pragma off (unreferenced)
|
---|
293 | void WAVEAUDIO::ConfigDev(STREAM *stream, PWAVECONFIGINFO pConfigInfo)
|
---|
294 | #pragma on (unreferenced)
|
---|
295 | {
|
---|
296 | ULONG ulCount, ulConsumeRate, ulBytesPerIRQ;
|
---|
297 |
|
---|
298 | // Set the clock select bits (_ucClockData)
|
---|
299 |
|
---|
300 | // Set up _ucFormatData and write usSilence for the WAVESTREAM
|
---|
301 | switch (pConfigInfo->ulDataType) {
|
---|
302 | case DATATYPE_WAVEFORM:
|
---|
303 | case PCM:
|
---|
304 | if (pConfigInfo->ulBitsPerSample == 16) {
|
---|
305 | pConfigInfo->usSilence = 0x0000;
|
---|
306 | }
|
---|
307 | else {
|
---|
308 | pConfigInfo->usSilence = 0x8080;
|
---|
309 | }
|
---|
310 | break;
|
---|
311 |
|
---|
312 | case DATATYPE_ALAW:
|
---|
313 | case DATATYPE_RIFF_ALAW:
|
---|
314 | case A_LAW:
|
---|
315 | pConfigInfo->usSilence = 0x5555;
|
---|
316 | break;
|
---|
317 |
|
---|
318 | case DATATYPE_MULAW:
|
---|
319 | case DATATYPE_RIFF_MULAW:
|
---|
320 | case MU_LAW:
|
---|
321 | pConfigInfo->usSilence = 0x7F7F;
|
---|
322 | break;
|
---|
323 | } /* endswitch */
|
---|
324 |
|
---|
325 | // Set the Stereo bit if necessary
|
---|
326 | // if (pConfigInfo->ulNumChannels == 2)
|
---|
327 | // _ucFormatData |= STEREO_BIT;
|
---|
328 |
|
---|
329 | // calculate the count register value: _usCountData
|
---|
330 | // according to the CS4232 Spec the Upper and Lower Base registers are
|
---|
331 | // loaded with the number of samples - 1 to be transfered between interrupts
|
---|
332 | // (for all data formats except ADPCM)
|
---|
333 | // For All Devices :
|
---|
334 | // We want to generate 32 interrupts per second but if this requires that
|
---|
335 | // we copy more than 0x0800 bytes of data per irq. Then we recalculate
|
---|
336 | // If more that 0x0800 bytes is transfered per interrupt then there
|
---|
337 | // may be problems with apps that use DART and stream small buffers
|
---|
338 |
|
---|
339 | ulCount = pConfigInfo->ulSampleRate;
|
---|
340 | ulCount >>= 5;
|
---|
341 | ulBytesPerIRQ = ulCount;
|
---|
342 | _usCountData = (USHORT)(ulCount -1);
|
---|
343 |
|
---|
344 | // Calculate the BytesPerIRQ
|
---|
345 | // The BytesPerIRQ is the number of bytes consumed by this data format
|
---|
346 | // for every interrupt generated by the codec.
|
---|
347 | // This inforamtion is returned to the WAVESTREAM which uses it in
|
---|
348 | // buffer management decisions....
|
---|
349 |
|
---|
350 | if (pConfigInfo->ulBitsPerSample == 16)
|
---|
351 | ulBytesPerIRQ <<= 1;
|
---|
352 | if (pConfigInfo->ulNumChannels == 2)
|
---|
353 | ulBytesPerIRQ <<= 1;
|
---|
354 | pConfigInfo->ulBytesPerIRQ = ulBytesPerIRQ;
|
---|
355 |
|
---|
356 | // Check that we are at or below 0x800 bytes per irq
|
---|
357 | // if not reclaculate based on 0x800 bytes per irq
|
---|
358 |
|
---|
359 | if (ulBytesPerIRQ > 0x00000800) {
|
---|
360 | ulCount = 0x00000800;
|
---|
361 | pConfigInfo->ulBytesPerIRQ = 0x00000800;
|
---|
362 | if (pConfigInfo->ulBitsPerSample == 16)
|
---|
363 | ulCount >>= 1;
|
---|
364 | if (pConfigInfo->ulNumChannels == 2)
|
---|
365 | ulCount >>= 1;
|
---|
366 | _usCountData = (USHORT)(ulCount -1);
|
---|
367 | }
|
---|
368 |
|
---|
369 | // Calculate the PCMConsumeRate
|
---|
370 | // The consume rate is the number of bytes consumed by this data format
|
---|
371 | // per second. It calculated by taking the following equation:
|
---|
372 | // sampling rate * (BitsPerSample/8) * NumChannels
|
---|
373 | // This info is returned to the WAVESTREAM and used to calculate stream time
|
---|
374 |
|
---|
375 | ulConsumeRate = pConfigInfo->ulSampleRate;
|
---|
376 | if (pConfigInfo->ulBitsPerSample == 16)
|
---|
377 | ulConsumeRate <<= 1;
|
---|
378 | if (pConfigInfo->ulNumChannels == 2)
|
---|
379 | ulConsumeRate <<= 1;
|
---|
380 | pConfigInfo->ulPCMConsumeRate = ulConsumeRate;
|
---|
381 |
|
---|
382 | }
|
---|
383 | /**@internal Pause
|
---|
384 | * @param None
|
---|
385 | * @return int 1
|
---|
386 | * @notes
|
---|
387 | * stub function pause is implemented as a stop by the stream
|
---|
388 | */
|
---|
389 | #pragma off (unreferenced)
|
---|
390 | int WAVEAUDIO::Pause(STREAM *stream)
|
---|
391 | #pragma on (unreferenced)
|
---|
392 | {
|
---|
393 | return 1;
|
---|
394 | }
|
---|
395 | /**@internal Resume
|
---|
396 | * @param None
|
---|
397 | * @return int 1
|
---|
398 | * @notes
|
---|
399 | * stub function resume is implemented as a start by the stream
|
---|
400 | */
|
---|
401 | #pragma off (unreferenced)
|
---|
402 | int WAVEAUDIO::Resume(STREAM *stream)
|
---|
403 | #pragma on (unreferenced)
|
---|
404 | {
|
---|
405 | return 1;
|
---|
406 | }
|
---|
407 |
|
---|
408 | #pragma code_seg ("_inittext");
|
---|
409 | #pragma data_seg ("_initdata","endds");
|
---|
410 |
|
---|
411 | /**@internal
|
---|
412 | * @param
|
---|
413 | * @return
|
---|
414 | * @notes
|
---|
415 | *
|
---|
416 | */
|
---|
417 | void WAVEAUDIO::_vSetup()
|
---|
418 | {
|
---|
419 | }
|
---|