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

  1. //
  2. // audiobuf.c
  3. // 27-Jan-99
  4. //
  5. //
  6. // static USHORT AllocMem(ULONG bufferSize, AUDIOBUFFER *audioBufferPtr);
  7. // static ULONG GetStartOffset(AUDIOBUFFER *audioBufferPtr);
  8. // VOID   abReset(USHORT mode, AUDIOBUFFER *audioBufferPtr);
  9. // ULONG  abSpace(AUDIOBUFFER *audioBufferPtr);
  10. // ULONG  abBytes(AUDIOBUFFER *audioBufferPtr);
  11. // ULONG  abUpdate(USHORT flags, AUDIOBUFFER *audioBufferPtr);
  12. // ULONG  abWrite(UCHAR __far *dataPtr, ULONG dataSize, AUDIOBUFFER *audioBufferPtr);
  13. // ULONG  abRead(UCHAR __far *dataPtr, ULONG dataSize, AUDIOBUFFER *audioBufferPtr);
  14. // VOID   abFill(USHORT fillWith, AUDIOBUFFER *audioBufferPtr);
  15. // VOID   abDeinit(AUDIOBUFFER *audioBufferPtr);
  16. // USHORT abInit(ULONG bufferSize, ULONG pageSize, USHORT dmaChannel, AUDIOBUFFER *audioBufferPtr);
  17.  
  18. #include "cs40.h"
  19.  
  20. PFN Device_Help = 0;
  21.  
  22. // ---------------
  23. // in: bufferSize, amount of physical memory to allocate (not all likely will be usuable)
  24. //out: rc (PDD says only rc=87 is possible error code)
  25. //nts: seems they all use this, and request above 1MB first, then under 1MB if none there
  26. //     may always be < 16MB here?  since DMA won't work if it's past 16MB mark
  27. //     only allocates raw physical memory, still need to massage it before using
  28.  
  29. static USHORT AllocMem(ULONG bufferSize, AUDIOBUFFER *audioBufferPtr) {
  30.  
  31.  USHORT rc;
  32.  ULONG physAddr;
  33.  
  34.  rc = DevHelp_AllocPhys(bufferSize, MEMTYPE_ABOVE_1M, &physAddr);
  35.  if (rc) rc = DevHelp_AllocPhys(bufferSize, MEMTYPE_BELOW_1M ,&physAddr);
  36.  if (rc == 0) {
  37.     audioBufferPtr->bufferPhysAddrRaw = physAddr; // won't change
  38.     audioBufferPtr->bufferPhysAddr = physAddr;    // will be forced to next 64K alignment
  39.  }
  40.  
  41.  return rc;
  42. }
  43.  
  44.  
  45. // ------------------
  46. // in: audioBufferPtr
  47. //out: offset of next start
  48. //nts: gets offset in audio buffer of where next read/write operation should start
  49.  
  50. static ULONG GetStartOffset(AUDIOBUFFER *audioBufferPtr) {
  51.  
  52.  ULONG t = audioBufferPtr->bufferBytes % audioBufferPtr->bufferSize;
  53.  
  54.  return t;
  55. }
  56.  
  57.  
  58. // ------------------
  59. // in: mode = read or write
  60. //     audioBufferPtr
  61. //out: n/a
  62. //nts: reset the audio buffer (was named InitBuffer)
  63.  
  64. VOID abReset(USHORT mode, AUDIOBUFFER *audioBufferPtr) {
  65.  
  66.  audioBufferPtr->mode = mode;
  67.  audioBufferPtr->deviceBytes = 0;
  68.  audioBufferPtr->bufferBytes = 0;
  69.  
  70.  return;
  71. }
  72.  
  73.  
  74. // ------------------
  75. // in: audioBufferPtr
  76. //out: good bytes
  77. //nts: gets bytes available in write audio buffer / valid bytes in read audio buffer
  78. //     original had _fGetSpace() called only by BufferStatus() (no point), so just coding
  79. //     BufferStatus() -- i.e., this returns the "good data" in the buffer (on a read or
  80. //     capture) or the "room left" in the buffer (on a write or play)
  81. //     original name was also BufferStatus()
  82.  
  83. ULONG abSpace(AUDIOBUFFER *audioBufferPtr) {
  84.  
  85.  ULONG t;
  86.  
  87.  if (audioBufferPtr->mode == AUDIOBUFFER_WRITE) {
  88.     t = audioBufferPtr->bufferSize - (audioBufferPtr->bufferBytes - audioBufferPtr->deviceBytes); // bytes available in buffer (write to dev, play)
  89.  }
  90.  else {
  91.     t = audioBufferPtr->deviceBytes - audioBufferPtr->bufferBytes;  // valid data bytes in buffer (read from dev, capture)
  92.  }
  93.  
  94.  return t;
  95. }
  96.  
  97.  
  98. // ------------------
  99. // in: audioBufferPtr
  100. //out: bytes written|read
  101. //nts: returns total number of bytes written to (playback mode) or read from (record mode) device
  102.  
  103. ULONG abBytes(AUDIOBUFFER *audioBufferPtr) {
  104.  
  105.  ULONG t = audioBufferPtr->bufferBytes;
  106.  
  107.  return t;
  108. }
  109.  
  110.  
  111. // ---------------
  112. // in: flags (was ULONG)
  113. //     audioBufferPtr
  114. //out: data consumed or produced
  115. //nts: called by the stream to get the "latest" number of bytes consumed|produced by device
  116. //     Flags is either 0 or not 0: if not 0 the audio buffer will call into the hardware
  117. //     (in this case dma object) and get the latest number of bytes value
  118.  
  119. ULONG abUpdate(USHORT flags, AUDIOBUFFER *audioBufferPtr) {
  120.  
  121.  if (flags) {
  122.     audioBufferPtr->deviceBytes = audioBufferPtr->deviceBytes + dmaQueryDelta(audioBufferPtr);
  123.  }
  124.  
  125.  return audioBufferPtr->deviceBytes;
  126. }
  127.  
  128.  
  129. // ---------------------------
  130. // in: dataPtr -> data to play
  131. //     dataSize = bytes in buffer
  132. //     audioBufferPtr
  133. //out: bytes actually written to buffer
  134. //nts: (was called WriteBuffer())
  135. //     writes data into the audio buffer (for it to be played)
  136. //     This should be called by a stream that is doing a playback -- this will only
  137. //     do the write based on the data returned by GetSpace/GetStartOffset
  138. //     BufferUpdate should be called before this routine
  139.  
  140. ULONG abWrite(UCHAR __far *dataPtr, ULONG dataSize, AUDIOBUFFER *audioBufferPtr) {
  141.  
  142.  ULONG abSize = audioBufferPtr->bufferSize;
  143.  ULONG startOffset = GetStartOffset(audioBufferPtr);
  144.  ULONG bytes = min(dataSize, abSpace(audioBufferPtr));
  145.  
  146.  if (bytes >= abSize) bytes = abSize;  // max limit is physical buffer size
  147.  bytes = bytes & ALIGN_FILL_PLAY;      // align now, after above
  148.  if (bytes == 0) goto ExitNow;         // shouldn't happen, unless abSpace() is 0, which it won't
  149.  
  150.  // if this write will wrap the buffer, split it up and do 2 writes
  151.  
  152.  if ((startOffset + bytes) > abSize) {
  153.  
  154.     ULONG diff = abSize - startOffset;
  155.  
  156.     MEMCPY(audioBufferPtr->bufferPtr+startOffset, dataPtr, diff);
  157.     MEMCPY(audioBufferPtr->bufferPtr, dataPtr+diff, bytes-diff);
  158.  
  159. // !!!
  160. // won't get here when doing ALIGN_FILL_PLAY size that's an even multiple of buffer
  161.  
  162. //tracePerf(128,(ULONG)audioBufferPtr->bufferPtr+startOffset);
  163. //tracePerf(129,(ULONG)dataPtr);
  164.  
  165.  }
  166.  else {
  167.     MEMCPY(audioBufferPtr->bufferPtr+startOffset, dataPtr, bytes);
  168.  }
  169.  
  170.  audioBufferPtr->bufferBytes = audioBufferPtr->bufferBytes + bytes;
  171.  
  172. ExitNow:
  173.  
  174.  return bytes;
  175. }
  176.  
  177.  
  178. // ---------------------------
  179. // in: dataPtr -> data to read
  180. //     dataSize = bytes in buffer
  181. //     audioBufferPtr
  182. //out: bytes actually read from buffer
  183. //nts: (was called ReadBuffer())
  184. //     reads data from the audio buffer (it was recorded)
  185. //     This should be called by a stream that is doing a record -- this will only
  186. //     do the read based on the data returned by GetSpace/GetStartOffset
  187. //     BufferUpdate should be called before this routine
  188.  
  189. ULONG abRead(UCHAR __far *dataPtr, ULONG dataSize, AUDIOBUFFER *audioBufferPtr) {
  190.  
  191.  ULONG abSize = audioBufferPtr->bufferSize;
  192.  ULONG startOffset = GetStartOffset(audioBufferPtr);
  193.  ULONG bytes = min(dataSize, abSpace(audioBufferPtr));
  194.  
  195.  if (bytes >= abSize) bytes = abSize;  // max limit is physical buffer size
  196.  bytes = bytes & ALIGN_FILL_CAPTURE;   // align now, after above
  197.  if (bytes == 0) goto ExitNow;         // shouldn't happen, unless abSpace() is 0, which it won't
  198.  
  199.  if ((startOffset + bytes) > abSize) {
  200.  
  201.     ULONG diff = abSize - startOffset;
  202.  
  203.     MEMCPY(dataPtr, audioBufferPtr->bufferPtr+startOffset, diff);
  204.     MEMCPY(dataPtr+diff, audioBufferPtr->bufferPtr, bytes-diff);
  205.  }
  206.  else {
  207.     MEMCPY(dataPtr, audioBufferPtr->bufferPtr+startOffset, bytes);
  208.  }
  209.  
  210.  audioBufferPtr->bufferBytes = audioBufferPtr->bufferBytes + bytes;
  211.  
  212. ExitNow:
  213.  return bytes;
  214. }
  215.  
  216.  
  217. // -------------------------------------
  218. // in: fillWith = word to use as filler
  219. //     audioBufferPtr
  220. //out: n/a
  221. //nts: seems to be no case where filler is not byte-symetrical, nevertheless,
  222. //     MEMSET() will write full words to buffer so -could- send 7FFF as a 16-bit filler
  223. //     idea here is to fill buffer with silence data, for as much as there is room
  224.  
  225. VOID abFill(USHORT fillWith, AUDIOBUFFER *audioBufferPtr) {
  226.  
  227.  ULONG bytes = abSpace(audioBufferPtr);
  228.  ULONG startOffset = GetStartOffset(audioBufferPtr);
  229.  
  230.  // if doing a capture the value returned by abSpace() is the data in the buffer ready to
  231.  // be copied out -- therefore, the amount to fill is that amount subtracted from the buffer size
  232.  
  233.  if (audioBufferPtr->mode == AUDIOBUFFER_READ) bytes = audioBufferPtr->bufferSize - bytes;
  234.  
  235.  MEMSET(audioBufferPtr->bufferPtr+startOffset, fillWith, bytes);
  236.  
  237.  return;
  238. }
  239.  
  240.  
  241. // -------------------------------------
  242. // in: audioBufferPtr
  243. //out: n/a
  244. //nts: destructor
  245. //     free the GDT first?  probably doesn't matter
  246.  
  247. VOID abDeinit(AUDIOBUFFER *audioBufferPtr) {
  248.  
  249.  DevHelp_FreePhys(audioBufferPtr->bufferPhysAddrRaw);
  250.  DevHelp_FreeGDTSelector(audioBufferPtr->sel);
  251.  
  252.  return;
  253. }
  254.  
  255.  
  256. #pragma code_seg ("_INITTEXT");
  257. #pragma data_seg ("_INITDATA","ENDDS");
  258.  
  259. // -------------------------------------
  260. // in: bufferSize = size of DMA to allocate
  261. //     pageSize = size of page for hardware (DMA or PCI, so probably different if PCI?)
  262. //     dma channel = for this audio buffer
  263. //     audioBufferPtr
  264. //out: n/a
  265. //nts: constructor
  266. //     sets things up ... give her a feather she's a cheroke
  267. //     careful not to call this when really mean to call abReset()
  268. //     originally passed flags as arg, not dmaChannel
  269.  
  270. USHORT abInit(ULONG bufferSize, ULONG pageSize, USHORT dmaChannel, AUDIOBUFFER *audioBufferPtr) {
  271.  
  272.  USHORT rc = 0;
  273.  USHORT flags;
  274.  ULONG tBufferSize, tBufferStart, tBufferEnd;
  275.  
  276.  audioBufferPtr->bufferSize = bufferSize;    // initial use, can vary per stream (ab.bufferSize)
  277.  
  278.  switch(dmaChannel) {
  279.  case 0:
  280.  case 1:
  281.  case 3:
  282.     flags = AUDIOBUFFER_ISA_DMA8;
  283.     tBufferSize = bufferSize + bufferSize;   // double size
  284.     break;
  285.  case 5:
  286.  case 6:
  287.  case 7:
  288.     flags = AUDIOBUFFER_ISA_DMA16;
  289.     tBufferSize = bufferSize + 0x20000;      // 128KB + requested size
  290.     break;
  291.  case 99:
  292.     flags = AUDIOBUFFER_DDMA;
  293.     tBufferSize = bufferSize;                // actual size
  294.     break;
  295.  default:
  296.     rc = 1;
  297.  }
  298.  
  299.  if (rc == 0) {
  300.  
  301.     rc = AllocMem(tBufferSize, audioBufferPtr);
  302.  
  303.     if (rc == 0) {
  304.  
  305.        tBufferStart = audioBufferPtr->bufferPhysAddr;
  306.  
  307.        if (flags == AUDIOBUFFER_ISA_DMA8) { // check if fits wholly in 64K page
  308.           tBufferEnd = tBufferStart + bufferSize;
  309.           if ((tBufferEnd >> 16) != (tBufferStart >> 16)) tBufferStart = (tBufferEnd & 0xFFFF0000);
  310.           audioBufferPtr->bufferPhysAddr = tBufferStart;
  311.        }
  312.        else if (flags == AUDIOBUFFER_ISA_DMA16) { // force start on a 128K page
  313.           audioBufferPtr->bufferPhysAddr = (audioBufferPtr->bufferPhysAddr + bufferSize) & 0xFFFE0000;
  314.        }
  315.        //else if (flags == AUDIOBUFFER_DDMA) {
  316.        //   audioBufferPtr->bufferPhysAddr already set okay
  317.        //}
  318.  
  319.        // allocate  a GDT
  320.  
  321.        rc = DevHelp_AllocGDTSelector(&audioBufferPtr->sel,1);
  322.  
  323.        if (rc == 0) {
  324.  
  325.           // map the physical memory to the GDT
  326.  
  327.           rc = DevHelp_PhysToGDTSelector(audioBufferPtr->bufferPhysAddr,
  328.                                          (USHORT)audioBufferPtr->bufferSize,
  329.                                          audioBufferPtr->sel);
  330.  
  331.           if (rc == 0) audioBufferPtr->bufferPtr = MAKEP(audioBufferPtr->sel,0);
  332.        }
  333.     }
  334.  }
  335.  
  336.  if (rc) {
  337.     if (audioBufferPtr->bufferPhysAddrRaw) {
  338.        DevHelp_FreePhys(audioBufferPtr->bufferPhysAddrRaw);
  339.        audioBufferPtr->bufferPhysAddrRaw = 0;
  340.     }
  341.     if (audioBufferPtr->sel) {
  342.        DevHelp_FreeGDTSelector(audioBufferPtr->sel);
  343.        audioBufferPtr->sel = 0;
  344.     }
  345.  }
  346.  
  347.  audioBufferPtr->deviceBytes = 0; // should already be
  348.  audioBufferPtr->bufferBytes = 0; // should already be
  349.  
  350.  return rc;
  351.  pageSize;
  352. }
  353.  
  354.  
  355.