home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / audiopdd.zip / wavaudio.c < prev    next >
C/C++ Source or Header  |  1999-02-27  |  15KB  |  427 lines

  1. //
  2. // wavaudio.c
  3. // 27-Jan-99
  4. //
  5. // VOID   waDevCaps(MCI_AUDIO_CAPS __far *devCapsPtr, WAVEAUDIO *waPtr);
  6. // VOID   waConfigDev(WAVECONFIG *waveConfigPtr, WAVEAUDIO *waPtr);
  7. // USHORT waPause(VOID);
  8. // USHORT waResume(VOID);
  9. // USHORT waSetup(USHORT dmaChannel, WAVEAUDIO *waPtr);
  10. //
  11. // _usfind_matching_sample_rate() and
  12. // _vset_clock_info() only called here, once, so done at caller rather than separate routines
  13.  
  14. #include "cs40.h"
  15.  
  16. // local defines for PCM, muLAW, and aLAW tables used by virtual void DevCaps(PAUDIO_CAPS pCaps)
  17.  
  18. #define NUMFREQS   4
  19. #define BPSTYPES   2
  20. #define MONOSTEREO 2
  21.  
  22. // local sample rate to clock-select bits
  23.  
  24. typedef struct _SRT {
  25.  USHORT sampleRate;     // 00 (was ULONG)
  26.  UCHAR  clockSelect;    // 02
  27.  UCHAR  rsv3;           // 03 reserved (can be used as multiplier flag for freq if need freq > 65535)
  28. } SRT;
  29.  
  30. // This table holds all the sample rates the CS4232 can operate at and the data required
  31. // in bits 0-3 of the FS and Playback Data Format Reg, (indexed register 8) to set them up
  32.  
  33. static SRT srt[] = {
  34.   5512,0x01,0,  6615,0x0f,0,  8000,0x00,0,  9600,0x0e,0, 11025,0x03,0,
  35.  16000,0x02,0, 18900,0x05,0, 22050,0x07,0, 27428,0x04,0, 32000,0x06,0,
  36.  33075,0x0D,0, 37800,0x09,0, 44100,0x0B,0, 48000,0x0C,0};
  37.  
  38. #define SRT_COUNT (sizeof(srt)/sizeof(SRT))
  39.  
  40. // the following 3-D array defines the subtypes for DATATYPE_WAVEFORM
  41. // The array is 4x2x2 and is indexed using frequency index, bits per
  42. // sample being 8 or 16 represented by 0 or 1 resp. and mono or stereo
  43. // mode represented by 0 or 1 respectively. For eg. to find out the
  44. // subtype for 22050Hz sampling frequency, using 16 bits per sample
  45. // and stereo mode, we use waveSubtypes[FREQ22KHZ][BPS16][1].
  46.  
  47. static USHORT waveSubtypes[NUMFREQS][BPSTYPES][MONOSTEREO] = { // was ULONG
  48.  WAVE_FORMAT_1M08,    // 11.025kHz, 8-bit  Mono
  49.  WAVE_FORMAT_1S08,    // 11.025kHz, 8-bit  Stereo
  50.  WAVE_FORMAT_1M16,    // 11.025kHz, 16-bit Mono
  51.  WAVE_FORMAT_1S16,    // 11.025kHz, 16-bit Stereo
  52.  WAVE_FORMAT_2M08,    // 22.05kHz , 8-bit  Mono
  53.  WAVE_FORMAT_2S08,    // 22.05kHz , 8-bit  Stereo
  54.  WAVE_FORMAT_2M16,    // 22.05kHz , 16-bit Mono
  55.  WAVE_FORMAT_2S16,    // 22.05kHz , 16-bit Stereo
  56.  WAVE_FORMAT_4M08,    // 44.1kHz  , 8-bit  Mono
  57.  WAVE_FORMAT_4S08,    // 44.1kHz  , 8-bit  Stereo
  58.  WAVE_FORMAT_4M16,    // 44.1kHz  , 16-bit Mono
  59.  WAVE_FORMAT_4S16,    // 44.1kHz  , 16-bit Stereo
  60.  WAVE_FORMAT_8M08,    //  8.0kHz  , 8-bit  Mono
  61.  WAVE_FORMAT_8S08,    //  8.0kHz  , 8-bit  Stereo
  62.  WAVE_FORMAT_8M16,    //  8.0kHz  , 16-bit Mono
  63.  WAVE_FORMAT_8S16     //  8.0kHz  , 16-bit Stereo
  64. };
  65.  
  66. // the following 2-D array defines the subtypes for DATATYPE_ALAW  it is indexed by the
  67. // sampling rate ordinal (from _usfind_matching_sample_rate) and the number of channels
  68.  
  69. static USHORT aLaw[NUMFREQS][MONOSTEREO] = { // was ULONG
  70.  ALAW_8B11KM,      // 8bit 11kHz mono
  71.  ALAW_8B11KS,      // 8bit 11kHz stereo
  72.  ALAW_8B22KM,      // 8bit 22kHz mono
  73.  ALAW_8B22KS,      // 8bit 22kHz stereo
  74.  ALAW_8B44KM,      // 8bit 44kHz mono
  75.  ALAW_8B44KS,      // 8bit 44kHz stereo
  76.  ALAW_8B8KM ,      // 8bit 8kHz mono
  77.  ALAW_8B8KS        // 8bit 8kHz stereo
  78. };
  79.  
  80. // the following 2-D array defines the subtypes for DATATYPE_MULAW it is indexed by the
  81. // sampling rate ordinal (from _usfind_matching_sample_rate) and the number of channels
  82.  
  83. static USHORT muLaw[NUMFREQS][MONOSTEREO] = { // was ULONG
  84.  MULAW_8B11KM,     // 8bit 11kHz mono
  85.  MULAW_8B11KS,     // 8bit 11kHz stereo
  86.  MULAW_8B22KM,     // 8bit 22kHz mono
  87.  MULAW_8B22KS,     // 8bit 22kHz stereo
  88.  MULAW_8B44KM,     // 8bit 44kHz mono
  89.  MULAW_8B44KS,     // 8bit 44kHz stereo
  90.  MULAW_8B8KM ,     // 8bit 8kHz mono
  91.  MULAW_8B8KS       // 8bit 8kHz stereo
  92. };
  93.  
  94. // sampleRates[] used by _usfind_matching_sample_rate() to determine sampling rate ordinal
  95.  
  96. USHORT sampleRates[] = {11025, 22050, 44100, 8000};  // all that's supported!? (yes, weird order)
  97.  
  98. #define SR_COUNT (sizeof(sampleRates)/sizeof(USHORT))
  99.  
  100. // following takes positive arguments and returns the absolute difference between the two args
  101.  
  102. #define DELTA(x,y) ((x > y) ? x - y : y - x)
  103.  
  104.  
  105. // --------------------
  106. // in: devCapsPtr -> audio caps structure passed from IoctlAudioCapability() call (was PAUDIO_CAPS, in audio.h)
  107. //out: n/a
  108. //nts:
  109.  
  110. VOID waDevCaps(MCI_AUDIO_CAPS __far *devCapsPtr) {
  111.  
  112.  USHORT sampleRate;
  113.  USHORT sampleRateIndex = 0;
  114.  USHORT tbps, tch, isFD;
  115.  
  116.  if (devCapsPtr->ulOperation == OPERATION_RECORD) {
  117.     isFD = war.flags & FLAGS_WAVEAUDIO_FULLDUPLEX;
  118.  }
  119.  else if (devCapsPtr->ulOperation == OPERATION_PLAY) {
  120.     isFD = wap.flags & FLAGS_WAVEAUDIO_FULLDUPLEX;
  121.  }
  122.  else {
  123.     devCapsPtr->ulSupport = UNSUPPORTED_OPERATION;      // (since can't record+play on SAME stream)
  124.     return;
  125.  }
  126.  
  127.  if (devCapsPtr->ulChannels > 2) {
  128.     devCapsPtr->ulSupport = UNSUPPORTED_CHANNELS;
  129.     return;
  130.  }
  131.  
  132.  if (devCapsPtr->ulBitsPerSample != 8 && devCapsPtr->ulBitsPerSample != 16) {
  133.     devCapsPtr->ulSupport = UNSUPPORTED_BPS;
  134.     return;
  135.  }
  136.  
  137.  sampleRate = (USHORT)devCapsPtr->ulSamplingRate;
  138.  if (1) {
  139.     USHORT i, diff, minDiff = 65535;
  140.     for (i=0; i < (sizeof(sampleRates)/sizeof(sampleRates[0])); i++) {
  141.        diff = DELTA(sampleRate, sampleRates[i]);
  142.        if (diff < minDiff) {
  143.           minDiff = diff;
  144.           sampleRateIndex = i;
  145.        }
  146.     }
  147.     sampleRate = sampleRates[sampleRateIndex];
  148.     if (sampleRate != (USHORT)devCapsPtr->ulSamplingRate) {
  149.        devCapsPtr->ulSamplingRate = sampleRate;                      // yup, update original
  150.        devCapsPtr->ulFlags = devCapsPtr->ulFlags | BESTFIT_PROVIDED; // ugh!
  151.  
  152. // !!!
  153. //ddprintf("waDevCaps: using BESTFIT sampleRate\n");
  154.  
  155.     }
  156.  }
  157.  
  158.  // get ulDataSubType and update any format-specific flags
  159.  // note: all data types have more than one value
  160.  
  161.  tbps = (devCapsPtr->ulBitsPerSample-8)/8;      // 0 or 1 (for 8 or 16)
  162.  tch  = devCapsPtr->ulChannels - 1;             // 0 or 1 (for mono or stereo)
  163.  
  164.  switch (devCapsPtr->ulDataType) {
  165.  case DATATYPE_WAVEFORM:
  166.  case PCM:
  167.     devCapsPtr->ulDataSubType = (ULONG)waveSubtypes[sampleRateIndex][tbps][tch];
  168.     //if (tbps) devCapsPtr->ulFlags = devCapsPtr->ulFlags | TWOS_COMPLEMENT | SIGNED; //16-bit is alway 2's-comp
  169. // !!! see if this matters
  170.     if (tbps) devCapsPtr->ulFlags = devCapsPtr->ulFlags | TWOS_COMPLEMENT;
  171.     break;
  172.  
  173.  case DATATYPE_ALAW:
  174.  case DATATYPE_RIFF_ALAW:
  175.  case A_LAW:
  176.     devCapsPtr->ulDataSubType = (ULONG)aLaw[sampleRateIndex][tch];
  177.     break;
  178.  
  179.  case DATATYPE_MULAW:
  180.  case DATATYPE_RIFF_MULAW:
  181.  case MU_LAW:
  182.     devCapsPtr->ulDataSubType = (ULONG)muLaw[sampleRateIndex][tch];
  183.     break;
  184.  
  185.  default:
  186.     devCapsPtr->ulSupport = UNSUPPORTED_DATATYPE;
  187.     return;
  188.  }
  189.  
  190.  // original had this overwrite the ulFlags above! (TWOS_COMP and BESTFIT_!)
  191.  // also, original (tropez) sets TWOS_COMP for 8-bit! data, in WAVESTREAM constructor
  192.  // also, original sets BIG_ENDIAN (4232 says 16-bit is little endian)
  193.  // ... not sure if this is saying what should be used, or what -can- be used (as in BIG_ENDIAN supported)
  194.  
  195. // !!!
  196.  devCapsPtr->ulFlags = devCapsPtr->ulFlags |
  197.                               BIG_ENDIAN |      // !!! that's what tropez has
  198.                               FIXED        |  // fixed length data
  199.                               LEFT_ALIGNED |  // left align bits on byte (always is if 8/16 bps)
  200.                               INPUT        |  // input select is supported
  201.                               OUTPUT       |  // output select is supported
  202.                               MONITOR      |  // monitor is supported
  203.                               VOLUME;         // volume control is supported
  204.  
  205.  // full-duplex info:
  206.  // The number of resource units is described in the MMPM2.INI -- this can be thought of as
  207.  // the number of active streams the driver can manage at one time.   Use 2 (one play, one rec).
  208.  //
  209.  // Tell MMPM how many of these units THIS stream will consume.  If full-duplex allowed, this
  210.  // stream consumes 1 stream unit.  If not allowed, indicate that this stream consumes 2 units
  211.  // (or all the available units).
  212.  //
  213.  // Along with the resource units, 2 resources classes are defined:  one for playback and one
  214.  // for capture.  Tell MMPM (in the MMPM2.INI) that driver can deal with 1 playback and 1 capture
  215.  // stream, OR 1 capture and 1 playback stream, at the same time. This is indicated in the
  216.  // valid resource combos in MMPM2.INI
  217.  //
  218.  // So, check if this is a playback or capture and set the correct resource class
  219.  // (playback = 1, capture = 2)
  220.  //
  221.  // no longer have WAVEAUDIO.usDmaChan/usSecDmaChan, but instead just WAVEAUDIO.flags bit0=1 is F-D
  222.  
  223.  if (isFD) {
  224.     devCapsPtr->ulResourceUnits = 1;
  225.  }
  226.  else {
  227.     devCapsPtr->ulResourceUnits = 2;   // full-duplex not allowed so allocate both resource units
  228.  }
  229.  
  230.  if (devCapsPtr->ulOperation == OPERATION_RECORD) {
  231.     devCapsPtr->ulResourceClass = 2;
  232.  }
  233.  else {
  234.     devCapsPtr->ulResourceClass = 1;
  235.  }
  236.  
  237.  devCapsPtr->fCanRecord = 1;
  238.  devCapsPtr->ulBlockAlign = 1;
  239.  devCapsPtr->ulSupport = SUPPORT_SUCCESS;
  240.  
  241. // !!!
  242. //ddprintf("@waDevCaps: devCapsPtr->ulFlags=%lx\n", devCapsPtr->ulFlags);
  243.  
  244.  return;
  245. }
  246.  
  247.  
  248. // ---------------------------------
  249. // in: wsPtr -> wavestream structure
  250. //out:
  251. //nts: also reinits dma hardware (esp. for logical dma buffer size, interrupts/buffer)
  252.  
  253. VOID waConfigDev(WAVESTREAM *wsPtr) {
  254.  
  255.  ULONG i, count, consumeRate;
  256.  USHORT tbps, tch, tBytesPS, tIs16, tIsST;
  257.  USHORT bufferInts;
  258.  USHORT dmaType;
  259.  
  260.  WAVECONFIG *waveConfigPtr = &wsPtr->waveConfig;
  261.  WAVEAUDIO *waPtr = wsPtr->waPtr;
  262.  
  263. // !!! new dma stuff
  264.  
  265.  waPtr->ab.bufferSize = wsPtr->audioBufferSize; // dma buffer size for this stream (def=0, 16KB)
  266.  if (waPtr->ab.bufferSize < 1024) waPtr->ab.bufferSize = 0x4000;
  267.  
  268.  bufferInts = wsPtr->audioBufferInts;           // interrupts per dma buffer (def=0, two per buffer)
  269.  if (bufferInts < 2) bufferInts = 2;            // at least two (must be a power of 2)
  270.  
  271. // !!!
  272. bufferInts = 8;
  273.  
  274.  tbps = waveConfigPtr->bitsPerSample;
  275.  tBytesPS = tbps/8;
  276.  tIs16 = tBytesPS >> 1;
  277.  
  278.  tch  = waveConfigPtr->channels;
  279.  tIsST = tch >> 1;
  280.  
  281.  // set clock select bits, using first SRT with sample rate >= requested rate
  282.  // eg, if req=44000 then uses 44100 (if req=2000 then uses 5512)
  283.  // this was done in a call to _vset_clock_info(ULONG freq)
  284.  
  285.  for (i=0; i < SRT_COUNT; i++) {
  286.     if (srt[i].sampleRate >= waveConfigPtr->sampleRate) {
  287.        waPtr->clockSelectData = srt[i].clockSelect;
  288.        break; // out of for
  289.     }
  290.     waPtr->clockSelectData = srt[SRT_COUNT-1].clockSelect;  // requested is > last srt, so use last
  291.  }
  292.  
  293.  // set up WAVEAUDIO.formatData, set silence data, set mono/stereo
  294.  
  295.  switch (waveConfigPtr->dataType) {
  296.  case DATATYPE_WAVEFORM:
  297.  case PCM:
  298.     if (tIs16) {
  299.        waPtr->formatData = FORMAT_BIT0;
  300.        waveConfigPtr->silence = 0x0000;
  301.     }
  302.     else {
  303.        waPtr->formatData = 0;
  304.        waveConfigPtr->silence = 0x8080;
  305.     }
  306.     break;
  307.  
  308.  case DATATYPE_ALAW:
  309.  case DATATYPE_RIFF_ALAW:
  310.  case A_LAW:
  311.     waPtr->formatData = FORMAT_BIT0 | CL_BIT;
  312.     waveConfigPtr->silence = 0x5555;
  313.     break;
  314.  
  315.  case DATATYPE_MULAW:
  316.  case DATATYPE_RIFF_MULAW:
  317.  case MU_LAW:
  318.     waPtr->formatData = CL_BIT;
  319.     waveConfigPtr->silence = 0x7F7F;
  320.     break;
  321.  }
  322.  
  323.  if (tIsST) waPtr->formatData = waPtr->formatData | STEREO_BIT;  // set stereo bit
  324.  
  325.  count = waPtr->ab.bufferSize/bufferInts;// bytes per interrupt
  326.  waveConfigPtr->bytesPerIRQ = count;    // grab it while it's still bytes
  327.  if (tIs16) count = count >> 1;         // if 16-bit then half as many as that in samples
  328.  if (tIsST) count = count >> 1;         // if stereo then half as many as that in samples again
  329.  waPtr->countData = count-1;            // samples per interrupt
  330.  
  331. // !!!
  332. ddprintf("@waConfigDev:count=%lxh, bytes/IRQ=%lxh\n",count,waveConfigPtr->bytesPerIRQ);
  333.  
  334.  // calc PCM consume rate
  335.  // The consume rate is the number of bytes consumed by this data format per second, based on:
  336.  //    rate = sampleRate * bps/8 * channels
  337.  // this is returned to the WAVESTREAM and used to calculate stream time
  338.  
  339.  consumeRate = waveConfigPtr->sampleRate;
  340.  if (tIs16) consumeRate = consumeRate + consumeRate;
  341.  if (tIsST) consumeRate = consumeRate + consumeRate;
  342.  waveConfigPtr->consumeRate = consumeRate;
  343.  
  344.  // reinit dma
  345.  // (dmaType has extra meaning: typeFdma is at bit8, so add it in (set in original dmaInit())
  346.  
  347.  dmaType = waPtr->ab.dmaCh.type | ((waPtr->ab.dmaCh.chInfo.typeFdma & 1) << 8);
  348.  dmaInit(waPtr->ab.dmaCh.ch, dmaType, &waPtr->ab);
  349.  
  350.  return;
  351. }
  352.  
  353.  
  354. // ---------------
  355. // in: n/a (maybe)
  356. //out: 1 always
  357. //nts: not used (use Stop stream instead)
  358.  
  359. USHORT waPause(VOID) {
  360.  
  361.  return 1;
  362. }
  363.  
  364.  
  365. // ---------------
  366. // in: n/a (maybe)
  367. //out: 1 always
  368. //nts: not used (use Start stream instead)
  369.  
  370. USHORT waResume(VOID) {
  371.  
  372.  return 1;
  373. }
  374.  
  375.  
  376. #pragma code_seg ("_INITTEXT");
  377. #pragma data_seg ("_INITDATA","ENDDS");
  378.  
  379.  
  380. // -----------------------------
  381. // in: dma channel = dma channel
  382. //     waPtr -> WAVEAUDIO structure for this object
  383. //out: 0 if okay, else error
  384. //nts: called by wpInit() and wrInit(), each of which have their own, single WAVEAUDIO structure
  385. //     and then only once, at driver init
  386. //     sets up:
  387. //      1. audioBuffer allocation and init
  388. //      2. dma init
  389. //     on entry, waPtr->flags:
  390. //      FLAGS_WAVEAUDIO_FULLDUPLEX  1   // can do full-duplex (has separate DMA for play/rec)
  391. //      FLAGS_WAVEAUDIO_DMA16       2   // dma channel is 16-bit (and waPtr->dmaPtr->ch itself)
  392. //      FLAGS_WAVEAUDIO_FTYPEDMA    4   // hardware support demand-mode dma
  393. //     passing dmaChannel to simplify
  394. //     was _vSetup()
  395.  
  396. USHORT waSetup(USHORT dmaChannel, WAVEAUDIO *waPtr) {
  397.  
  398.  USHORT rc = 0;
  399.  USHORT typeDMA = DMA_TYPE_ISA; // will be OR'ed with DMA_TYPE_PLAY(dma-read)/CAPTURE(dma-write)
  400.  ULONG  sizeDMA = DMA_BUFFER_SIZE;  // physical size, will be xxKB always (after testing)
  401.  ULONG  sizePage = 0; // 0 because...dunno, not used I suppose
  402.  
  403.  rc = abInit(sizeDMA, sizePage, dmaChannel, &waPtr->ab);
  404.  if (rc) goto ExitNow;
  405.  
  406.  if (waPtr->devType == AUDIOHW_WAVE_PLAY) {
  407.     typeDMA = typeDMA | DMA_TYPE_PLAY;
  408.  }
  409.  else {
  410.     typeDMA = typeDMA | DMA_TYPE_CAPTURE;
  411.  }
  412.  
  413.  if (waPtr->flags & FLAGS_WAVEAUDIO_FTYPEDMA) {
  414.     typeDMA = typeDMA | DMA_TYPE_FTYPE;
  415.  }
  416.  
  417.  rc = dmaInit(dmaChannel, typeDMA, &waPtr->ab);
  418.  if (rc) goto ExitNow;
  419.  
  420.  waPtr->irqHandlerPtr = (NPFN)irqHandler;  // assign near function pointer to IRQ handler (always CS:offset)
  421.  
  422. ExitNow:
  423.  return rc;
  424. }
  425.  
  426.  
  427.