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

  1. //
  2. // wavestrm.c
  3. // 27-Jan-99
  4. //
  5. // 19-Feb-99 removed bogus reference/use of controlPtr->
  6. //
  7. // VOID    wavestreamProcess(WAVESTREAM *wsPtr);
  8. // ULONG   wavestreamGetCurrentTime(WAVESTREAM *wsPtr);
  9. // VOID    wavestreamSetCurrentTime(ULONG time, WAVESTREAM *wsPtr);
  10. // USHORT  wavestreamStart(WAVESTREAM *wsPtr);
  11. // USHORT  wavestreamStop(WAVESTREAM *wsPtr);
  12. // USHORT  wavestreamPause(WAVESTREAM *wsPtr);
  13. // USHORT  wavestreamResume(WAVESTREAM *wsPtr);
  14. // STREAM *wavestreamInit(USHORT streamType, MCI_AUDIO_INIT __far *mciInitPtr, WAVESTREAM *wsPtr);
  15. // USHORT  wavestreamDeinit(WAVESTREAM *wsPtr);
  16.  
  17. #include "cs40.h"
  18.  
  19. static USHORT RealignBuffer(ULONG endPos, STREAM_BUFFER *sbPtr);
  20. static VOID RealignPausedBuffers(WAVESTREAM *wsPtr);
  21. static VOID ResetAudioBuffer(WAVESTREAM *wsPtr);
  22. static VOID FillAudioBuffer(WAVESTREAM *wsPtr);
  23. static ULONG WriteAudioBuffer(WAVESTREAM *wsPtr);
  24. static ULONG ReadAudioBuffer(WAVESTREAM *wsPtr);
  25.  
  26. // ---------------------------------
  27. // in: wsPtr -> WAVESTREAM structure
  28. //out: n/a
  29. //nts: process irq
  30. //     called at interrupt time from the hardware objects' handler (waveplay handler, etc.)
  31. //     if buffers on proc queue get/put them ...
  32. //     (was Process)
  33. //     original notes follow (there was no _vUpdateProcessed() routine):
  34. //     --first call _vUpdateProcessed() to update the dma amd audio buffer related
  35. //     --stuff. Next if we have buffers on the primary queue try to read/write them
  36. //     --to the audiobuffer. Look at the buffers on the done queue and see if they
  37. //     --can be returned and finally process any events pending.
  38.  
  39. VOID wavestreamProcess(WAVESTREAM *wsPtr) {
  40.  
  41.  STREAM_BUFFER *sbPtr;
  42.  STREAM *streamPtr = wsPtr->streamPtr;
  43.  USHORT streamMode = wsPtr->streamPtr->streamType & STREAM_RW_MODE;
  44.  
  45.  wsPtr->bytesProcessed = abUpdate(1, &wsPtr->waPtr->ab);  // get 'final' stream byte consumed/produced count
  46.  
  47.  if (streamMode == STREAM_WRITE) {           // playback
  48.  
  49. // even undoing this only brought it down to 58%!
  50. // so pretty-much rem'ed out all of the irq (just resets int and bye!)...it runs at 58%
  51. // don't know what the hell's going on
  52.  
  53.     if (sbNotEmpty(&streamPtr->sbaProc)) {   // if buffer in proc queue...
  54.        FillAudioBuffer(wsPtr);               // keep audio buffer full
  55.     }
  56.  
  57.     // if there are buffers that have been completely written to the audio buffer
  58.     // check the first one on the done queue to see if the hardware has consumed it
  59.     // and if so return it
  60.  
  61. // rem'ing out the return-buffer stuff below only went from 66% down to 60% or so...hm
  62. // now checking the FillAudioBuffer section above (rem'ing it out--will get back tomorrow
  63. // in any case) ... if that's not it, have to check ssm_idc stuff next
  64.  
  65.  
  66. // should see about doing this out of interrupt context, via arm context hook (18-Feb-99)
  67. // since it calls back to SHDD and ints are enabled there
  68.  
  69.     if (sbNotEmpty(&streamPtr->sbaDone)) {   
  70.        sbPtr = sbHead(&streamPtr->sbaDone);
  71.        if ((wsPtr->bytesProcessed + wsPtr->waveConfig.bytesPerIRQ) >= sbPtr->bufferDonePos) {
  72.           streamReturnBuffer(streamPtr);
  73.        }
  74.     }
  75.  
  76.  }
  77.  else { // STREAM_READ capture
  78.     ReadAudioBuffer(wsPtr);
  79.     while(sbNotEmpty(&streamPtr->sbaDone)) {
  80.        streamReturnBuffer(streamPtr);
  81.     }
  82.  }
  83.  
  84. // streamProcessEvents(streamPtr); // stub routine for now
  85.  
  86.  return;
  87. }
  88.  
  89.  
  90. // ---------------------------------
  91. // in: wsPtr -> WAVESTREAM structure
  92. //out: current time
  93. //nts: this calcs stream time in milliseconds based on...(?)
  94. //     -- time = bytes consumed / consume rate
  95. //
  96. //     IMPORTANT: often the use of this data is to not be returned directly, but
  97. //     a pointer to a variable that has its value (eg, wsPtr->currTime, or wsPtr->timeBase
  98. //     for control stop/pause) is returned instead (all DDCMD calls, but not SHD returns)
  99. //     -- if instead return the value directly all sorts of crap (silently) happens (19-Feb-99)
  100.  
  101. ULONG wavestreamGetCurrentTime(WAVESTREAM *wsPtr) {
  102.  
  103.  ULONG msecs = 0, processed;
  104.  USHORT flag = 0;
  105.  STREAM *streamPtr = wsPtr->streamPtr;
  106.  
  107.  if (streamPtr->streamState == STREAM_STREAMING) flag = 1; // check w/hardware only if running
  108.  processed = abUpdate(flag, &wsPtr->waPtr->ab);
  109.  
  110.  if (processed) {
  111.     ULONG c_rate = wsPtr->waveConfig.consumeRate;
  112.     ULONG secs = processed / c_rate;
  113.     ULONG ov =   processed - (secs * c_rate);
  114.     msecs = ((ov * 1000) / c_rate) + (secs * 1000);
  115.  }
  116.  
  117.  return msecs + wsPtr->timeBase;  // if nothing yet processed, effectively returns just time base
  118. }
  119.  
  120.  
  121. // -----------------------------------
  122. // in: time = ms time to set time base
  123. //     wsPtr -> WAVESTREAM structure
  124. //out: n/a
  125. //nts: mmpm/2 sends stream starting time (may not be 0) so use this as the time base
  126.  
  127. VOID wavestreamSetCurrentTime(ULONG time, WAVESTREAM *wsPtr) {
  128.  
  129.  wsPtr->timeBase = time;
  130.  
  131.  return;
  132. }
  133.  
  134.  
  135. // -----------------------------------
  136. // in: wsPtr -> WAVESTREAM structure
  137. //out: 0
  138. //nts:
  139.  
  140. USHORT wavestreamStart(WAVESTREAM *wsPtr) {
  141.  
  142.  USHORT rc = 0;
  143.  
  144.  // waveConfig.bitsPerSample, channels, sampleRate, and dataType, must be setup
  145.  // (which is done in wavestreamInit()) before calling waConfigDev()
  146.  
  147.  waConfigDev(wsPtr);
  148.  ResetAudioBuffer(wsPtr);
  149.  
  150.  if (wsPtr->waPtr->devType == AUDIOHW_WAVE_PLAY) {
  151.     rc = waveplayStart(wsPtr);
  152.  }
  153.  else {
  154.     rc = waverecStart(wsPtr);
  155.  }
  156.  
  157.  if (rc) {
  158.     rc = ERROR_START_STREAM;
  159.  }
  160.  else {
  161.     wsPtr->streamPtr->streamState = STREAM_STREAMING;
  162.  }
  163.  
  164.  return rc;
  165. }
  166.  
  167.  
  168. // -----------------------------------
  169. // in: wsPtr -> WAVESTREAM structure
  170. //out: 0
  171. //nts:
  172.  
  173. USHORT wavestreamStop(WAVESTREAM *wsPtr) {
  174.  
  175.  USHORT rc = 0;
  176.  
  177.  if (wsPtr->waPtr->devType == AUDIOHW_WAVE_PLAY) {
  178.     rc = waveplayStop(wsPtr);
  179.  }
  180.  else {
  181.     rc = waverecStop(wsPtr);
  182.  }
  183.  
  184.  streamReturnBuffers(wsPtr->streamPtr);
  185.  wsPtr->streamPtr->streamState = STREAM_STOPPED;
  186.  
  187.  wsPtr->timeBase = wavestreamGetCurrentTime(wsPtr); // local
  188.  
  189.  abReset(wsPtr->streamPtr->streamType & STREAM_RW_MODE, &wsPtr->waPtr->ab);
  190.  
  191.  return rc;
  192. }
  193.  
  194.  
  195. // -----------------------------------
  196. // in: wsPtr -> WAVESTREAM structure
  197. //out: 0
  198. //nts:
  199.  
  200. USHORT wavestreamPause(WAVESTREAM *wsPtr) {
  201.  
  202.  USHORT rc = 0;
  203.  
  204.  if (wsPtr->waPtr->devType == AUDIOHW_WAVE_PLAY) {
  205.     rc = waveplayStop(wsPtr);
  206.  }
  207.  else {
  208.     rc = waverecStop(wsPtr);
  209.  }
  210.  
  211.  wsPtr->streamPtr->streamState = STREAM_PAUSED;
  212.  RealignPausedBuffers(wsPtr);
  213.  
  214.  wsPtr->timeBase = wavestreamGetCurrentTime(wsPtr); // local
  215.  
  216.  abReset(wsPtr->streamPtr->streamType & STREAM_RW_MODE, &wsPtr->waPtr->ab);
  217.  
  218. // !!!
  219. // testing new dma stuff (can just change logical dma buffer size at will)
  220. //
  221. //if (wsPtr->audioBufferSize == 0) {
  222. //   wsPtr->audioBufferSize = 8192;
  223. //}
  224.  
  225.  return rc;
  226. }
  227.  
  228.  
  229. // -----------------------------------
  230. // in: wsPtr -> WAVESTREAM structure
  231. //out: 0
  232. //nts:
  233.  
  234. USHORT wavestreamResume(WAVESTREAM *wsPtr) {
  235.  
  236.  USHORT rc;
  237.  
  238.  // since the resume code is exactly the same as the start, just call start
  239.  
  240.  rc = wavestreamStart(wsPtr);  // this gets all of start inlined...
  241.  
  242.  return rc;
  243. }
  244.  
  245.  
  246. // -----------------------------------
  247. // in: streamType = AUDIOHW_WAVE_PLAY or _CAPTURE
  248. //     wsPtr -> WAVESTREAM structure, already allocated
  249. //out: n/a
  250. //nts:
  251. //     this called by "void IoctlAudioInit(PREQPACKET prp, USHORT LDev)"
  252. //     and should (I think) return a (STREAM *), which means the last
  253. //     thing this should do is call streamInit(...)
  254.  
  255. STREAM *wavestreamInit(USHORT streamType, MCI_AUDIO_INIT __far *mciInitPtr, WAVESTREAM *wsPtr) {
  256.  
  257.  USHORT rc = 0;
  258.  STREAM *tstreamPtr = malloc(sizeof(STREAM));   // this gets free'd in wavestreamDeinit()
  259.  
  260.  if (tstreamPtr) {
  261.  
  262.     MEMSET(tstreamPtr,0,sizeof(STREAM));
  263.  
  264.     rc = streamInit(streamType, tstreamPtr);
  265.     if (rc == 0) {
  266.  
  267.        tstreamPtr->wsParentPtr = wsPtr;
  268.  
  269.        // update WAVESTREAM
  270.  
  271.        wsPtr->streamPtr = tstreamPtr;
  272.  
  273.        // WAVEAUDIO waPtr-> data already setup (incl. dma, audiobuffer)
  274.        // but still need to set WAVESTREAM.waPtr -> wap (or war) structure (6-Feb-99)
  275.  
  276.        if (streamType == AUDIOHW_WAVE_PLAY) {
  277.           wsPtr->waPtr = &wap;
  278.        }
  279.        else {
  280.           wsPtr->waPtr = &war;
  281.        }
  282.  
  283.        //WAVECONFIG. data already setup, some of it? like silence
  284.  
  285.        abReset(streamType & STREAM_RW_MODE, &wsPtr->waPtr->ab);
  286.        wsPtr->waveConfig.sampleRate = (USHORT)mciInitPtr->lSRate;
  287.        wsPtr->waveConfig.bitsPerSample = (UCHAR)mciInitPtr->lBitsPerSRate;
  288.        wsPtr->waveConfig.channels = (UCHAR)mciInitPtr->sChannels;
  289.        wsPtr->waveConfig.dataType = mciInitPtr->sMode;
  290.  
  291.        wsPtr->audioBufferSize = 0;  // 0=use default logical DMA size
  292.        wsPtr->bytesProcessed = 0;
  293.        wsPtr->timeBase = 0;
  294.  
  295.        mciInitPtr->sSlotNumber = -1;
  296.        mciInitPtr->lResolution = 10;
  297.  
  298.        mciInitPtr->ulFlags = mciInitPtr->ulFlags | FIXED | LEFT_ALIGNED;
  299.  
  300.        // original had this if flags == 8...snafu (pas16 has 8 also)
  301.  
  302.        if (mciInitPtr->ulFlags == 16) {
  303.           mciInitPtr->ulFlags = mciInitPtr->ulFlags | TWOS_COMPLEMENT;
  304.        }
  305.     }
  306.  
  307.     // since rc only possible if streamInit() failed, don't need to use streamDeinit()
  308.     // but...streamInit() currently never fails...
  309.  
  310.     if (rc) {
  311.        free(tstreamPtr);
  312.        tstreamPtr = 0;
  313.     }
  314.  }
  315.  
  316.  return tstreamPtr;
  317. }
  318.  
  319. // ------------------
  320. // in:
  321. //out:
  322. //nts: deinit used rather than just doing this in streamDeinit
  323. //     just to reverse wavestreamInit() concept
  324.  
  325. USHORT wavestreamDeinit(WAVESTREAM *wsPtr) {
  326.  
  327.  USHORT rc = 0;
  328.  
  329.  streamDeinit(wsPtr->streamPtr);
  330.  free(wsPtr->streamPtr);
  331.  free(wsPtr);
  332.  
  333.  return rc;
  334. }
  335.  
  336.  
  337. // --------------------------
  338. // in: endPos
  339. //     sbPtr -> stream buffer
  340. //out:
  341. //nts:
  342. //
  343. //  _vRealignBuffer
  344. //  called just after a wave stream pause on a playback.
  345. //  Gets the end position of the stream when paused and a pointer to a
  346. //  STREAMBUFFER. Basicly this function looks at the streambuffer and if
  347. // there is any unplayed data in it it adjusts the bufpos counter.
  348. // the donepos counter is ALWAYS set to zero. It will return 0 if all
  349. // the data has been played and 1 if there is still some data left.
  350. //
  351. // note that sbPtr->sizes are being aligned with 0xFFFFFFFC, which should do fine (don't use ALIGN_FILL_...)
  352.  
  353. static USHORT RealignBuffer(ULONG endPos, STREAM_BUFFER *sbPtr) {
  354.  
  355.  USHORT rc = 1;
  356.  ULONG sbStart, consumed;
  357.  
  358.  sbStart = sbPtr->bufferDonePos - sbPtr->bufferCurrPos;
  359.  
  360.  if (endPos <= sbStart) {       // none of the data in this stream buffer has been consumed yet
  361.     sbPtr->bufferDonePos = 0;   
  362.     sbPtr->bufferCurrPos = 0;   
  363.     // rc = 1; already is
  364.  }
  365.  else {                         // some or all of the data has been consumed
  366.     consumed = endPos - sbStart;
  367.     if (consumed <= sbPtr->bufferSize) {        // some has been...
  368.        sbPtr->bufferDonePos = 0;
  369.  
  370. // !!!
  371. // not sure if this should be ALIGN_FILL_PLAY instead of 0xFFFFFFFC
  372. // but either this or the one in RealignBuffers() caused problem at pause if used FFFFFFFC
  373.  
  374.        //sbPtr->bufferCurrPos = (sbPtr->bufferSize-consumed) & 0xFFFFFFFC; //always keep dword-aligned
  375.        sbPtr->bufferCurrPos = (sbPtr->bufferSize-consumed) & ALIGN_FILL_PLAY;
  376.        // rc = 1; already is
  377.     }
  378.     else {                      // all has been...
  379.        sbPtr->bufferDonePos = 0;
  380.        sbPtr->bufferCurrPos = sbPtr->bufferSize;
  381.        rc = 0;
  382.     }
  383.  }
  384.  
  385.  return rc;
  386. }
  387.  
  388.  
  389. // ----------------------------------
  390. // in: wsPtr -> wave stream structure
  391. //out:
  392. //nts:
  393. //
  394. // _vRealignPausedBuffers(void)
  395. // When a stream is paused, have to "realign" the data in the audio buffer with reality, since:
  396. // - on playback, not all the data in the audio buffer has been consumed
  397. // - on capture, not all the good data in the audio buffer has been copied out
  398. //
  399. // After getting DDCMDCONTROL PAUSE cmd, this routine is called to line the MMPM buffers back up:
  400. // - for a capture stream: copy any data still in the audio buffer to an MMPM buffer
  401. // - for a playback stream:
  402. // -- check the STREAMBUFFER at proc queue to see if any unconsumed data is in the audio buffer
  403. //    if yes, back up bufferCurrPos (was ulBuffpos) in the STREAMBUFFER
  404. // -- check any STREAMBUFFERs on done queue, starting with the last one (the tail).
  405. //    if necessary, back up bufferCurrPos (was ulBuffpos) and put the STREAMBUFFER on the Head queue
  406.  
  407. static VOID RealignPausedBuffers(WAVESTREAM *wsPtr) {
  408.  
  409.  STREAM *streamPtr = wsPtr->streamPtr;
  410.  
  411.  if ((streamPtr->streamType & STREAM_RW_MODE) == STREAM_READ) {
  412.     ReadAudioBuffer(wsPtr);  // capture/recording
  413.  }
  414.  else {
  415.  
  416.     static STREAM_BUFFER_ANCHOR sbaTemp; // have to use static else gets "pointer truncated" warning
  417.                                          // which is probably a compiler bug (!) anyway, check later
  418.     STREAM_BUFFER *tsbPtr;
  419.     ULONG endPos;
  420.     USHORT rc;
  421.  
  422.     sbaTemp.headPtr = 0;
  423.     sbaTemp.tailPtr = 0;
  424.  
  425. // !!!
  426. // not sure if this should be ALIGN_FILL_PLAY instead of 0xFFFFFFFC
  427. // but either this or the one in RealignBuffer() caused problem at pause if used FFFFFFFC
  428.  
  429.     //endPos = (abUpdate(1, &wsPtr->waPtr->ab)) & 0xFFFFFFFC; // get 'final' stream byte consumed/produced count
  430.     endPos = (abUpdate(1, &wsPtr->waPtr->ab)) & ALIGN_FILL_PLAY; // get 'final' stream byte consumed count
  431.  
  432.     if (sbNotEmpty(&streamPtr->sbaProc)) {   // if buffer in proc queue...
  433.        tsbPtr = sbHead(&streamPtr->sbaProc); // ...only care about first since rest are waiting...
  434.        if (tsbPtr->bufferDonePos) {          // if any data has been written from this SB, realign
  435.           RealignBuffer(endPos, tsbPtr);
  436.        }
  437.     }
  438.  
  439.     // if buffers on the done queue, pop off head and push them on sbaTemp head
  440.     // this is to re-order them, putting the more recently used ones at the front of the queue
  441.     //
  442.     // pass all those (on sbaTemp queue) to RealignBuffer():
  443.     // -- if rc = 0: no unprocessed data in the buffer (ready to be returned as-is)
  444.     //    so it gets put on the tail of the done queue
  445.     // -- if rc = 1: put it on head of in-process queue
  446.  
  447.     while (sbNotEmpty(&streamPtr->sbaDone)) {
  448.        tsbPtr = sbPopHead(&streamPtr->sbaDone);
  449.        sbPushOnHead(tsbPtr, &sbaTemp);
  450.     }
  451.  
  452.     while (sbNotEmpty(&sbaTemp)) {
  453.        tsbPtr = sbHead(&sbaTemp);
  454.        rc = RealignBuffer(endPos, tsbPtr);
  455.        tsbPtr = sbPopHead(&sbaTemp);
  456.        if (rc == 0) {   
  457.           sbPushOnTail(tsbPtr, &streamPtr->sbaDone); // buffer is done
  458.        }
  459.        else {           
  460.           sbPushOnHead(tsbPtr, &streamPtr->sbaProc); // buffer has more
  461.        }
  462.     }
  463.  }
  464.  
  465.  return;
  466. }
  467.  
  468.  
  469. // ---------------------------------
  470. // in: wsPtr -> WAVESTREAM structure
  471. //out: n/a
  472. //nts: prepare to stream
  473. //     (was _vInitAudioBuf)
  474.  
  475. static VOID ResetAudioBuffer(WAVESTREAM *wsPtr) {
  476.  
  477.  AUDIOBUFFER *abPtr = &wsPtr->waPtr->ab;
  478.  USHORT streamMode = wsPtr->streamPtr->streamType & STREAM_RW_MODE;
  479.  
  480.  abReset(streamMode, abPtr);            // reset audiobuffer
  481.  if (streamMode == STREAM_WRITE) {
  482.     FillAudioBuffer(wsPtr);
  483.  }
  484.  else {
  485.     abFill(wsPtr->waveConfig.silence, abPtr);
  486.  }
  487.  
  488.  return;
  489. }
  490.  
  491.  
  492. // ---------------------------------
  493. // in: wsPtr -> WAVESTREAM structure
  494. //out: n/a
  495. //nts: fill audio buffer with as much data as possible (for playback)
  496. //     align on 256 bytes sizes though, using ALIGN_FILL_PLAY
  497. //     was _vFillAudioBuf
  498.  
  499. static VOID FillAudioBuffer(WAVESTREAM *wsPtr) {
  500.  
  501.  ULONG space;
  502.  ULONG bytesWritten = 0;        // just for tracePerf
  503.  STREAM *streamPtr = wsPtr->streamPtr;
  504.  AUDIOBUFFER *abPtr = &wsPtr->waPtr->ab;
  505.  
  506.  // while have process buffers and there is space in the audio buffer, write data to the audio buffer
  507.  
  508. #ifdef TRACE_FILLAUDIOBUFFER
  509.  tracePerf(TRACE_FILLAUDIOBUFFER_IN, _IF());
  510. #endif
  511.  
  512.  space = abSpace(abPtr) & ALIGN_FILL_PLAY;
  513.  
  514.  while(space && sbNotEmpty(&streamPtr->sbaProc)) {
  515.     bytesWritten = bytesWritten + WriteAudioBuffer(wsPtr);  // bytesWritten just for tracePerf
  516.     space = abSpace(abPtr) & ALIGN_FILL_PLAY;
  517.  }
  518.  
  519. #ifdef TRACE_FILLAUDIOBUFFER
  520.  tracePerf(TRACE_FILLAUDIOBUFFER_OUT, (bytesWritten << 16) | _IF());  //
  521. #endif
  522.  
  523.  return;
  524. }
  525.  
  526.  
  527. // ---------------------------------
  528. // in: wsPtr -> WAVESTREAM structure
  529. //out: n/a
  530. //nts: write one buffer to the audio buffer
  531. //     caller must ensure that it's okay to write to the audio buffer
  532. //     -- this assumes there's room and that there's a buffer on proc queue
  533. //     (was _vAudioBufWrite)
  534.  
  535. static ULONG WriteAudioBuffer(WAVESTREAM *wsPtr) {
  536.  
  537.  UCHAR __far *dataBufferPtr;
  538.  ULONG bufferLeft, bytesWritten, startPos;
  539.  
  540.  STREAM_BUFFER *sbPtr;
  541.  STREAM *streamPtr  = wsPtr->streamPtr;
  542.  AUDIOBUFFER *abPtr = &wsPtr->waPtr->ab;
  543.  
  544.  sbPtr =    sbHead(&streamPtr->sbaProc);
  545.  startPos = abBytes(abPtr);   // could just do "startPos = abPtr->bufferBytes;" (all routine does)
  546.  
  547.  dataBufferPtr = sbPtr->bufferPtr + sbPtr->bufferCurrPos;
  548.  bufferLeft    = sbPtr->bufferSize - sbPtr->bufferCurrPos;
  549.  
  550.  bytesWritten  = abWrite(dataBufferPtr, bufferLeft, abPtr);  // write to the audio buffer
  551.  
  552.  sbPtr->bufferDonePos = startPos + bytesWritten;  // store bytes written (updated in pause if needed)
  553.  sbPtr->bufferCurrPos = sbPtr->bufferCurrPos + bytesWritten; // update position according to Garp
  554.  
  555.  // check if this emptied the buffer (check on dword align in case last buffer, which may not be)
  556.  // if it's empty put it on the tail of the Done queue
  557.  
  558.  if (sbPtr->bufferCurrPos >= (sbPtr->bufferSize & 0xFFFFFFFC)) {
  559.     STREAM_BUFFER *tsbPtr = sbPopHead(&streamPtr->sbaProc);
  560.     sbPushOnTail(tsbPtr, &streamPtr->sbaDone);
  561.  }
  562.  
  563.  return bytesWritten; // just so can use it for tracePerf
  564. }
  565.  
  566.  
  567. // ---------------------------------
  568. // in: wsPtr -> WAVESTREAM structure
  569. //out: n/a
  570. //nts: read recorded data from the audio buffer
  571. //     called at interrupt time (via wavestreamProcess())
  572. //     (was _vReadAudioBuf)
  573.  
  574. static ULONG ReadAudioBuffer(WAVESTREAM *wsPtr) {
  575.  
  576.  UCHAR __far *dataBufferPtr;
  577.  ULONG bufferLeft, space, bytesRead;
  578.  ULONG totBytes = 0;  // need separate var since bytesRead used in loop
  579.  
  580.  STREAM_BUFFER *sbPtr;
  581.  STREAM *streamPtr  = wsPtr->streamPtr;
  582.  AUDIOBUFFER *abPtr = &wsPtr->waPtr->ab;
  583.  
  584.  space = abSpace(abPtr) & ALIGN_FILL_CAPTURE;   // was not here at all before
  585.  while(space && sbNotEmpty(&streamPtr->sbaProc)) {
  586.  
  587.     sbPtr = sbHead(&streamPtr->sbaProc);
  588.  
  589.     dataBufferPtr = sbPtr->bufferPtr + sbPtr->bufferCurrPos;
  590.     bufferLeft    = sbPtr->bufferSize - sbPtr->bufferCurrPos;
  591.  
  592.     bytesRead = abRead(dataBufferPtr, bufferLeft, abPtr);  // read from the audio buffer
  593.     totBytes = totBytes + bytesRead;  // for tracePerf
  594.  
  595.     sbPtr->bufferCurrPos = sbPtr->bufferCurrPos + bytesRead; // update position according to Garp
  596.  
  597.     // check if this emptied the buffer (check on dword align in case last buffer, which may not be)
  598.     // if it's empty put it on the tail of the Done queue
  599.  
  600.     if (sbPtr->bufferCurrPos >= (sbPtr->bufferSize & 0xFFFFFFFC)) {
  601.        STREAM_BUFFER *tsbPtr = sbPopHead(&streamPtr->sbaProc);
  602.        sbPushOnTail(tsbPtr, &streamPtr->sbaDone);
  603.     }
  604.  
  605.     space = abSpace(abPtr) & ALIGN_FILL_CAPTURE;  // was & 0xFFFFFFFC;;
  606.  }
  607.  
  608.  return totBytes;
  609. }
  610.  
  611.  
  612.  
  613.