source: cmedia/trunk/Drv16/waudio.cpp@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 16.7 KB
Line 
1/* $Id: waudio.cpp,v 1.2 2001/04/30 21:07:59 sandervl Exp $ */
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#include <sbvsd.h>
27
28#include <linux/soundcard.h>
29
30#include "waudio.hpp"
31#include "ossidc.h"
32
33
34
35// Rudi: no support for ALAW and MULAW formats
36#define NO_xLAW
37
38
39// the following 3-D array defines the subtypes for DATATYPE_WAVEFORM
40// The array is 4x2x2 and is indexed using frequency index, bits per
41// sample being 8 or 16 represented by 0 or 1 resp. and mono or stereo
42// mode represented by 0 or 1 respectively. For eg. to find out the
43// subtype for 22050Hz sampling frequency, using 16 bits per sample
44// and stereo mode, we use aaulWave[FREQ22KHZ][BPS16][1]. This avoids
45// inefficient nested if's and switches to find a matching value given
46// the same.
47//
48USHORT aaulWave[NUMFREQS][BPSTYPES][MONOSTEREO] = {
49 WAVE_FORMAT_1M08, /* 11.025kHz, 8-bit Mono */
50 WAVE_FORMAT_1S08, /* 11.025kHz, 8-bit Stereo */
51 WAVE_FORMAT_1M16, /* 11.025kHz, 16-bit Mono */
52 WAVE_FORMAT_1S16, /* 11.025kHz, 16-bit Stereo */
53 WAVE_FORMAT_2M08, /* 22.05kHz , 8-bit Mono */
54 WAVE_FORMAT_2S08, /* 22.05kHz , 8-bit Stereo */
55 WAVE_FORMAT_2M16, /* 22.05kHz , 16-bit Mono */
56 WAVE_FORMAT_2S16, /* 22.05kHz , 16-bit Stereo */
57 WAVE_FORMAT_4M08, /* 44.1kHz , 8-bit Mono */
58 WAVE_FORMAT_4S08, /* 44.1kHz , 8-bit Stereo */
59 WAVE_FORMAT_4M16, /* 44.1kHz , 16-bit Mono */
60 WAVE_FORMAT_4S16, /* 44.1kHz , 16-bit Stereo */
61 WAVE_FORMAT_8M08, /* 8.0kHz , 8-bit Mono */
62 WAVE_FORMAT_8S08, /* 8.0kHz , 8-bit Stereo */
63 WAVE_FORMAT_8M16, /* 8.0kHz , 16-bit Mono */
64 WAVE_FORMAT_8S16 /* 8.0kHz , 16-bit Stereo */
65 };
66
67/*
68USHORT aaulMPEG[NUMFREQS][MONOSTEREO] = {
69 MPEG1_FORMAT_3M16, // 11.025kHz Mono
70 MPEG1_FORMAT_3S16, // 11.025kHz Stereo
71 MPEG1_FORMAT_3M16, // 22.05kHz Mono
72 MPEG1_FORMAT_3S16, // 22.05kHz Stereo
73 MPEG1_FORMAT_4M16, // 44.1kHz / 48kHz Mono
74 MPEG1_FORMAT_4S16, // 44.1kHz / 48kHz Stereo
75 MPEG1_FORMAT_3M16, // 8.0kHz Mono
76 MPEG1_FORMAT_3S16, // 8.0kHz Stereo
77 };
78*/
79
80
81#ifndef NO_xLAW
82
83 // the following 2-D array defines the subtypes for DATATYPE_ALAW
84 // it is indexed by the sampling rate ordinal (from
85 // _usfind_matching_sample_rate) and the number of channels
86 USHORT aaulAlaw[NUMFREQS][MONOSTEREO] = {
87 ALAW_8B11KM, /* 8bit 11kHz mono*/
88 ALAW_8B11KS, /* 8bit 11kHz stereo*/
89 ALAW_8B22KM, /* 8bit 22kHz mono*/
90 ALAW_8B22KS, /* 8bit 22kHz stereo*/
91 ALAW_8B44KM, /* 8bit 44kHz mono*/
92 ALAW_8B44KS, /* 8bit 44kHz stereo*/
93 ALAW_8B8KM , /* 8bit 8kHz mono*/
94 ALAW_8B8KS /* 8bit 8kHz stereo*/
95 };
96
97 // the following 2-D array defines the subtypes for DATATYPE_MULAW
98 // it is indexed by the sampling rate ordinal (from
99 // _usfind_matching_sample_rate) and the number of channels
100 USHORT aaulMulaw[NUMFREQS][MONOSTEREO] = {
101 MULAW_8B11KM, /* 8bit 11kHz mono*/
102 MULAW_8B11KS, /* 8bit 11kHz stereo*/
103 MULAW_8B22KM, /* 8bit 22kHz mono*/
104 MULAW_8B22KS, /* 8bit 22kHz stereo*/
105 MULAW_8B44KM, /* 8bit 44kHz mono*/
106 MULAW_8B44KS, /* 8bit 44kHz stereo*/
107 MULAW_8B8KM , /* 8bit 8kHz mono*/
108 MULAW_8B8KS /* 8bit 8kHz stereo*/
109 };
110
111#endif
112
113/**@internal _usfind_matching_sample_rate
114 * @param PULONG pulSampleRate
115 * @return
116 * @notes
117 * The following function takes a sampling rate as input and finds out
118 * the closest sampling rate in 11KHz, 22KHz, 44KHz and 8KHz. It retuns
119 * the ordinal value of the matching sampling rate which should be used
120 * to reference an array element by the frequency index.
121 * This function is called by the DevCaps member function.
122 *
123 */
124
125// the following macro only takes positive arguments and returns the
126// absolute difference between the two arguments
127#define distance(x, y) ((x>y)? x-y : y-x)
128
129USHORT WAVEAUDIO::_usfind_matching_sample_rate(PULONG pulSampleRate)
130{
131 // The aulSuppSampleRates array is used by member function
132 // _usfind_matching_sample_rate to determine the sampling rate
133 // ordinal
134 static ULONG aulSuppSampleRates[NUMFREQS] = {11025, 22050, 44100, 8000};
135 ULONG ulDistance, ulMinDistance = 0x7fffffff;
136 USHORT us, usMatching;
137
138 for ( us = 0; us < NUMFREQS; us++ ) {
139 ulDistance = distance( *pulSampleRate, aulSuppSampleRates[us] );
140 if (ulDistance < ulMinDistance) {
141 ulMinDistance = ulDistance;
142 usMatching = us;
143 }
144 }
145 *pulSampleRate = aulSuppSampleRates[usMatching];
146 return usMatching;
147}
148
149/**@internal
150 * @param
151 * @return
152 * @notes
153 *
154 */
155void WAVEAUDIO::DevCaps(PAUDIO_CAPS pCaps)
156{
157 USHORT usSampleRateIndex, usChannelIndex;
158 ULONG ulSampleRate;
159
160// Rudi: moved from below
161 pCaps->ulFlags = FIXED | // Fixed length data
162 INPUT | // Input select is supported
163 OUTPUT | // Output select is supported
164 MONITOR | // Monitor is supported
165 VOLUME; // Volume control is supported
166
167 // This device driver supports Playback or Record Operations
168 // anything else makes no sence. Note: This a per stream operation so
169 // even if this sevice can do full-duplex, it can not do PLAY_AND_RECORD
170
171 if ( pCaps->ulOperation != OPERATION_PLAY &&
172 pCaps->ulOperation != OPERATION_RECORD ) {
173 pCaps->ulSupport = UNSUPPORTED_OPERATION;
174 return;
175 }
176
177 // Stereo or Mono only
178// Rudi: experimental 4 channel support
179 if( !(pCaps->ulChannels == 1 ||
180 pCaps->ulChannels == 2 ||
181 pCaps->ulChannels == 4 &&
182 pCaps->ulOperation == OPERATION_PLAY && pCaps->ulBitsPerSample == 16) )
183 {
184 pCaps->ulSupport = UNSUPPORTED_CHANNELS;
185 return;
186 }
187
188 // supported bits per sample are 8 (for unsigned PCM, u-law or A-law )
189 // and 16 (for 2's complement PCM)
190 if (pCaps->ulBitsPerSample != 8 && pCaps->ulBitsPerSample != 16) {
191 pCaps->ulSupport = UNSUPPORTED_BPS;
192 return;
193 }
194
195 //save the sampling rate called with
196 ulSampleRate = pCaps->ulSamplingRate;
197 if (ulSampleRate < 4000 || ulSampleRate > 56000 ) {
198 pCaps->ulSupport = UNSUPPORTED_RATE;
199 return;
200 }
201
202 // find out the closest sampling rate (may or may not be the same )
203 // from one of the following: 11025Hz, 22050Hz, 44100Hz and 8000Hz
204 // _usfind_matching_sample_rate will update pCaps->ulSamplingRate if there
205 // is not an exact match.
206 usSampleRateIndex = _usfind_matching_sample_rate(&pCaps->ulSamplingRate);
207 usChannelIndex = ( pCaps->ulChannels > 1 ) ? 1 : 0;
208
209 // If _usfind_matching_sample_rate changed the sampling rate set
210 // the best fit flag.
211 if (ulSampleRate != pCaps->ulSamplingRate)
212 pCaps->ulFlags |= BESTFIT_PROVIDED;
213
214 // Determine the ulDataSubType and update any format specific flags
215 // Note: All data types have more than one value.
216 switch ( (USHORT)pCaps->ulDataType ) {
217 case PCM:
218 case DATATYPE_WAVEFORM:
219 // determine subtype for PCM:
220 pCaps->ulDataSubType = aaulWave[usSampleRateIndex]
221 [(pCaps->ulBitsPerSample >> 3) - 1]
222 [usChannelIndex];
223 if (pCaps->ulBitsPerSample == 16)
224 pCaps->ulFlags |= TWOS_COMPLEMENT; // 2's complement data
225 break;
226
227 case DATATYPE_AC3:
228 if (pCaps->ulOperation == OPERATION_RECORD) {
229 pCaps->ulSupport = UNSUPPORTED_DATATYPE;
230 return;
231 }
232
233 pCaps->ulDataSubType = 0;
234 break;
235
236#ifndef NO_xLAW
237//SvL: Does the SB live hardware support this or is it just a limitation of the linux driver?
238 case A_LAW:
239 case DATATYPE_ALAW:
240 case DATATYPE_RIFF_ALAW:
241 // determine subtype for A_LAW
242 pCaps->ulDataSubType = aaulAlaw[usSampleRateIndex][usChannelIndex];
243 break;
244
245 case MU_LAW:
246 case DATATYPE_MULAW:
247 case DATATYPE_RIFF_MULAW:
248 // determine subtype for MU_LAW
249 pCaps->ulDataSubType = aaulMulaw[usSampleRateIndex][usChannelIndex];
250 break;
251#endif
252
253 default:
254 pCaps->ulSupport = UNSUPPORTED_DATATYPE;
255 return;
256 } // end switch
257
258
259 // Full Duplex Enabling Stuff here !!
260 // The number of resource units is described in the MMPM2.INI
261 // This can be thought of the number of active streams the
262 // driver can manage at one time. We list this number as 2.
263 // we tell MMPM here how many of these units THIS stream will consume.
264 // The answer is so simple it's brilliant, (Thanks to Joe Nord at Crystal
265 // Semi) If we are enabled to do full-duplex this stream will consume 1
266 // unit, If we are not enabled to do full-duplex this stream will consume 2
267 // (or all the available units)
268 // Along with the resource units, we defined 2 resources classes,
269 // one for playback and one for capture. We tell MMPM (in the MMPM2.INI)
270 // that we can handle doing 1 playback and 1 capture stream or 1 capture and
271 // one playback stream at the same time. (Valid Resource combos in the
272 // MMPM2.INI) check if we are a playback or capture and set the correct
273 // resource class (Playback = 1, Capture = 2)
274
275 pCaps->ulResourceUnits = 1;
276 pCaps->ulResourceClass = ( pCaps->ulOperation == OPERATION_PLAY ) ?
277 WAVE_PLAYBACK_CLASS : WAVE_RECORD_CLASS;
278
279// Rudi: Joe Nord said it so, docs say it's unused
280// pCaps->fCanRecord = 1; // Yes Virgina we can record
281 pCaps->fCanRecord = 0;
282
283// Rudi: align on "whole" samples
284// pCaps->ulBlockAlign = 1; // Block alignment for this mode
285 pCaps->ulBlockAlign = (pCaps->ulChannels * pCaps->ulBitsPerSample) >> 3;
286
287 //return success
288 pCaps->ulSupport = SUPPORT_SUCCESS;
289}
290
291/**@internal
292 * @param
293 * @return
294 * @notes
295 *
296 */
297void WAVEAUDIO::DevCaps(LPDAUDIO_CAPS lpCaps)
298{
299 lpCaps->dwFlags = DAUDIOCAPS_PRIMARYMONO |
300 DAUDIOCAPS_PRIMARYSTEREO |
301 DAUDIOCAPS_PRIMARY8BIT |
302 DAUDIOCAPS_PRIMARY16BIT |
303 DAUDIOCAPS_CONTINUOUSRATE |
304 DAUDIOCAPS_CERTIFIED |
305 DAUDIOCAPS_SECONDARYMONO |
306 DAUDIOCAPS_SECONDARYSTEREO |
307 DAUDIOCAPS_SECONDARY8BIT |
308 DAUDIOCAPS_SECONDARY16BIT;
309
310 lpCaps->dwMinSecondarySampleRate = 8000; //SBLIVECAPS_MINSAMPLERATE;
311 lpCaps->dwMaxSecondarySampleRate = 48000; //SBLIVECAPS_MAXSAMPLERATE;
312
313 lpCaps->dwMaxHwMixingAllBuffers = //SBLIVECAPS_MAXSTREAMS;
314 lpCaps->dwMaxHwMixingStaticBuffers = //SBLIVECAPS_MAXSTREAMS;
315 lpCaps->dwMaxHwMixingStreamingBuffers = //SBLIVECAPS_MAXSTREAMS;
316 lpCaps->dwPrimaryBuffers = 1;
317
318 lpCaps->dwMaxHw3DAllBuffers =
319 lpCaps->dwMaxHw3DStaticBuffers =
320 lpCaps->dwMaxHw3DStreamingBuffers =
321 lpCaps->dwFreeHw3DAllBuffers =
322 lpCaps->dwFreeHw3DStaticBuffers =
323 lpCaps->dwFreeHw3DStreamingBuffers =
324 lpCaps->dwTotalHwMemBytes =
325 lpCaps->dwFreeHwMemBytes =
326 lpCaps->dwMaxContigFreeHwMemBytes =
327 lpCaps->dwUnlockTransferRateHwBuffers =
328 lpCaps->dwPlayCpuOverheadSwBuffers =
329 lpCaps->dwReserved1 =
330 lpCaps->dwReserved2 = 0;
331}
332
333/**@internal
334 * @param
335 * @return
336 * @notes
337 *
338 */
339virtual void WAVEAUDIO::ConfigDev(STREAM *stream, PWAVECONFIGINFO pConfigInfo)
340{
341 FORMAT_INFO formatInfo;
342 ULONG /*ulCount, */ulConsumeRate, ulBytesPerIRQ, uSampleShift;
343
344 // Set the clock select bits (_ucClockData)
345
346 // Set up _ucFormatData and write usSilence for the WAVESTREAM
347 switch (pConfigInfo->usDataType) {
348 case PCM:
349 case DATATYPE_AC3:
350 case DATATYPE_WAVEFORM:
351 pConfigInfo->usSilence =
352 ( pConfigInfo->usBitsPerSample == 16 ) ? 0x0000 : 0x8080;
353 break;
354
355#ifndef NO_xLAW
356 case DATATYPE_ALAW:
357 case DATATYPE_RIFF_ALAW:
358 case A_LAW:
359 pConfigInfo->usSilence = 0x5555;
360 break;
361
362 case DATATYPE_MULAW:
363 case DATATYPE_RIFF_MULAW:
364 case MU_LAW:
365 pConfigInfo->usSilence = 0x7F7F;
366 break;
367#endif
368 } /* endswitch */
369
370 // Set the Stereo bit if necessary
371// if (pConfigInfo->usNumChannels == 2)
372// _ucFormatData |= STEREO_BIT;
373
374 uSampleShift = (pConfigInfo->usBitsPerSample == 16);
375
376 // For All Devices :
377 // We want to generate 32 interrupts per second but if this requires that
378 // we copy more than 0x0800 bytes of data per irq. Then we recalculate
379 // If more that 0x0800 bytes is transfered per interrupt then there
380 // may be problems with apps that use DART and stream small buffers
381
382 ulBytesPerIRQ = pConfigInfo->ulSampleRate >> 5;
383
384 // Calculate the BytesPerIRQ
385 // The BytesPerIRQ is the number of bytes consumed by this data format
386 // for every interrupt generated by the codec.
387 // This inforamtion is returned to the WAVESTREAM which uses it in
388 // buffer management decisions....
389
390// Rudi: experimental 4 channel support
391 ulBytesPerIRQ *= pConfigInfo->usNumChannels << uSampleShift;
392// if (pConfigInfo->usBitsPerSample == 16) ulBytesPerIRQ <<= 1;
393// if (pConfigInfo->usNumChannels == 2) ulBytesPerIRQ <<= 1;
394
395 if( ulBytesPerIRQ > 2048 ) ulBytesPerIRQ = 2048;
396 pConfigInfo->ulBytesPerIRQ = ulBytesPerIRQ;
397
398
399#if 0
400 // Check that we are at or below 0x800 bytes per irq
401 // if not reclaculate based on 0x800 bytes per irq
402
403 if (ulBytesPerIRQ > 0x00000800) {
404 ulCount = 0x00000800;
405 pConfigInfo->ulBytesPerIRQ = 0x00000800;
406
407// Rudi: experimental 4 channel support
408 ulCount /= pConfigInfo->usNumChannels << uSampleShift;
409// if (pConfigInfo->usBitsPerSample == 16) ulCount >>= 1;
410// if (pConfigInfo->usNumChannels == 2) ulCount >>= 1;
411
412 _usCountData = (USHORT)(ulCount -1);
413 }
414#endif
415
416
417 // Calculate the PCMConsumeRate
418 // The consume rate is the number of bytes consumed by this data format
419 // per second. It calculated by taking the following equation:
420 // sampling rate * (BitsPerSample/8) * NumChannels
421 // This info is returned to the WAVESTREAM and used to calculate stream time
422
423 ulConsumeRate = pConfigInfo->ulSampleRate;
424// Rudi: experimental 4 channel support
425 ulConsumeRate *= pConfigInfo->usNumChannels << uSampleShift;
426// if (pConfigInfo->usBitsPerSample == 16) ulConsumeRate <<= 1;
427// if (pConfigInfo->usNumChannels == 2) ulConsumeRate <<= 1;
428 pConfigInfo->ulPCMConsumeRate = ulConsumeRate;
429
430
431 formatInfo.ulSampleRate = pConfigInfo->ulSampleRate;
432 formatInfo.ulNumChannels = pConfigInfo->usNumChannels;
433 formatInfo.ulBitsPerSample = pConfigInfo->usBitsPerSample;
434
435 switch( pConfigInfo->usDataType )
436 {
437#ifndef NO_xLAW
438 case A_LAW:
439 case DATATYPE_ALAW:
440 case DATATYPE_RIFF_ALAW:
441 formatInfo.ulDataType = AFMT_A_LAW;
442 break;
443
444 case MU_LAW:
445 case DATATYPE_MULAW:
446 case DATATYPE_RIFF_MULAW:
447 formatInfo.ulDataType = AFMT_MU_LAW;
448 break;
449#endif
450
451 case DATATYPE_AC3:
452 formatInfo.ulDataType = 0x00000400L; // AFMT_AC3
453 break;
454
455 default:
456 formatInfo.ulDataType =
457 ( pConfigInfo->usBitsPerSample == 8 ) ? AFMT_U8 : AFMT_S16_LE;
458 }
459
460 OSS16_StreamSetFormat(stream, (ULONG)&formatInfo);
461}
462
463
464/**@internal Start
465 * @param None
466 * @return
467 * @notes
468 */
469int WAVEAUDIO::Start(STREAM *stream)
470{
471 return OSS16_StartStream(stream);
472}
473
474/**@internal Stop
475 * @param None
476 * @return
477 * @notes
478 */
479int WAVEAUDIO::Stop(STREAM *stream)
480{
481 return OSS16_StopStream(stream);
482}
483
484
485/**@internal Pause
486 * @param None
487 * @return int 1
488 * @notes
489 * stub function pause is implemented as a stop by the stream
490 */
491int WAVEAUDIO::Pause(STREAM */*stream*/)
492{
493 return 1;
494}
495
496/**@internal Resume
497 * @param None
498 * @return int 1
499 * @notes
500 * stub function resume is implemented as a start by the stream
501 */
502int WAVEAUDIO::Resume(STREAM */*stream*/)
503{
504 return 1;
505}
506
507
Note: See TracBrowser for help on using the repository browser.