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

Last change on this file since 553 was 553, checked in by rudi, 14 years ago

Adapt sourcecode to OpenWatcom

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 */
339void 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.