libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmAudioBuf.c 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmAudioPort.h"
  9. #include "cmAudioBuf.h"
  10. enum
  11. {
  12. kInIdx = 0;
  13. kOutIdx = 1;
  14. kIoCnt = 2;
  15. };
  16. typedef struct
  17. {
  18. cmApAudioPacket_t pkt; //
  19. char* buf; // buf[bufByteCnt]
  20. unsigned bufByteCnt; //
  21. } cmAudioBufDevBuf_t;
  22. typedef struct
  23. {
  24. cmAudioBufSubDev_t* subDevArray;
  25. unsigned subDevCnt;
  26. unsigned readyCnt;
  27. } cmAudioBufCycle_t;
  28. typedef struct
  29. {
  30. unsigned chCnt; // device channel count
  31. cmAudioBufCycle_t* cycleArray; // subBufArray[ subBufCnt ]
  32. unsigned cycleCnt; // set by cmAudioBufSetup().subBufCnt
  33. unsigned faultCnt; // count of overruns (input) underruns (output)
  34. unsigned iCycleIdx; // in: next buf to rcv on abUpdate() out: rcv on abGet()
  35. unsigned oCycleIdx; // in: next buf to send on abGet() out: send on abUpdate()
  36. unsigned fullCnt; // in: cnt of bufs ready for abGet() out: cnt of bufs ready for abUpdate()
  37. } cmAudioBufIO_t;
  38. typedef struct
  39. {
  40. cmAudioBufIO_t ioArray[kIoCnt];
  41. } cmAudioBufDev_t;
  42. typedef struct
  43. {
  44. cmErr_t err;
  45. unsigned devCnt;
  46. cmAudioBufDev_t* devArray; // devArray[ devCnt ]
  47. unsigned zeroBufByteCnt; // max of all possible buf sizes for all devices
  48. char* zeroBuf; // zeroBuf[ zeroBufByteCnt ]
  49. unsigned updateCnt;
  50. unsigned nextSeqId;
  51. } cmAudioBuf_t;
  52. cmAudioBuf_t _cmBa;
  53. cmBaRC_t cmAudioBufInit( cmCtx_t* ctx, unsigned devCnt )
  54. {
  55. cmBaRC_t rc = kOkBaRC;
  56. cmErrSetup(_cmBa.err,&ctx->rpt,"Audio Buf");
  57. _cmBa.devArray = cmMemAllocZ(cmAudioBufDev_t,devCnt);
  58. _cmBa.devCnt = devCnt;
  59. _cmBa.zeroBufByteCnt = 0;
  60. _cmBa.zeroBuf = NULL;
  61. _cmBa.updateCnt = 0;
  62. _cmBa.nextSeqId = 0;
  63. return rc;
  64. }
  65. cmBaRC_t _cmAudioBufIoFree( cmAudioBufIO_t* iop )
  66. {
  67. unsigned i;
  68. for(i=0; i<iop->subBufCnt; ++i)
  69. cmMemPtrFree(&iop->subBufArray[i].buf);
  70. cmMemPtrFree(&iop->subBufArray);
  71. return kOkBaRC;
  72. }
  73. cmBaRC_t cmAudioBufFinal()
  74. {
  75. cmBaRC_t rc = kOkBaRC;
  76. unsigned i,j;
  77. for(i=0; i<_cmBa.devCnt; ++i)
  78. for(j=0; j<kIoCnt; ++j)
  79. _cmAudioBufIoFree( _cmBa.devArray[i].ioArray + j );
  80. cmMemPtrFree(&_cmBa.devArray);
  81. _cmBa.devCnt = 0;
  82. cmMemPtrFree(&_cmBa.zeroBuf);
  83. _cmBa.zeroBufByteCnt = 0;
  84. }
  85. cmBaRC_t cmAudioBufSetup(
  86. unsigned devIdx,
  87. unsigned cycleCnt,
  88. unsigned inSubDevCnt,
  89. unsigned inChCnt,
  90. unsigned inFrameCnt,
  91. unsigned outChCnt,
  92. unsigned outFrameCnt,
  93. unsigned outSubDevCnt )
  94. {
  95. assert(devIdx < _cmBa.devCnt );
  96. cmAudioBufDev_t* dp = _cmBa.devArray + devIdx;
  97. unsigned i,j;
  98. for(i=0; i<kIoCnt; ++i)
  99. {
  100. cmAudioBufIO_t* iop = dp->ioArray + i;
  101. _cmAudioBufIoFree(iop);
  102. iop->subBufArray = cmMemAllocZ(cmAudioBufSubBuf_t,subBufCnt);
  103. iop->subBufCnt = 0;
  104. unsigned maxSampleWidthByteCnt = 4;
  105. // max size of any buffer arriving via cmAudioBufUpdate() for this device/direction
  106. unsigned bufByteCnt = frameCnt*chCnt*maxSampleWidthByteCnt;
  107. // initialize the sub-buf array for this device/direction
  108. for(j=0; j<subBufCnt; ++j)
  109. {
  110. iop->subBufArray[j].buf = cmMemAllocZ(char,bufByteCnt);
  111. iop->subBufArray[j].bufByteCnt = bufByteCnt;
  112. }
  113. // track the largest buffer size and make _cmBa.zeroBuf[] that size
  114. if( bufByteCnt > _cmBa.zeroBufByteCnt )
  115. {
  116. cmMemResizeZ(char,_cmBa.zeroBuf,bufByteCnt);
  117. _cmBa.zeroBufByteCnt = bufByteCnt;
  118. }
  119. }
  120. }
  121. // Called from the audio driver within incoming samples to store (inPktArray)
  122. // and empty buffers (outPktArray) to fill with outgoin samples.
  123. cmBaRC_t cmAudioBufUpdate(
  124. cmApAudioPacket_t* inPktArray, ///< full audio packets from incoming audio (from ADC)
  125. unsigned inPktCnt, ///< count of incoming audio packets
  126. cmApAudioPacket_t* outPktArray, ///< empty audio packet for outgoing audio (to DAC)
  127. unsigned outPktCnt ///< count of outgoing audio packets
  128. )
  129. {
  130. cmBaRC_t rc = kOkBaRC;
  131. ++_cmBa.updateCnt;
  132. unsigned i;
  133. for(i=0; i<inPktCnt && inPktArray!=NULL; ++i)
  134. {
  135. cmApAudioPacket_t* ipp = inPktArray + i;
  136. // get a pointer to the device/direction recd
  137. cmAudioBufIO_t* iop = _cmBa.devArray[ ipp->devIdx ].ioArray + kInIdx;
  138. // check for overruns
  139. if( iop->fullCnt == iop->subBufCnt )
  140. {
  141. // input overrun
  142. ++ip->faultCnt;
  143. rc = cmErrMsg(&_cmBa.err,kBufOverrunBaRC,"Input buffer overrun.");
  144. }
  145. else
  146. {
  147. // get the next available sub-buf
  148. cmAudioBufSubBuf_t* sbp = iop->subBufArray + iop->iSubBufIdx;
  149. // store the packet header
  150. sbp->pkt = *ipp;
  151. sbp->audioBytesPtr = sbp->buf;
  152. // calc the count of bytes of incoming packet audio
  153. unsigned pktBufByteCnt = ipp->chCnt * ipp->audioFramesCnt * (bitsPerSample/8);
  154. assert( pktBufByteCnt <= sbp->bufByteCnt );
  155. // copy the samples into the buffer
  156. memcpy(sbp->buf,ipp->audioBytesPtr,pktBufByteCnt);
  157. // advance the input sub-buffer
  158. iop->iSubBufIdx = (iop->iSubBufIdx + 1) % iop->subBufCnt;
  159. iop->fullCnt+=1;
  160. }
  161. }
  162. for(i=0; i<outPktCnt && outPktArray!=NULL; ++i)
  163. {
  164. unsigned j;
  165. cmApAudioPacket_t* opp = outPktArray + i;
  166. // get a pointer to the device/direction recd
  167. cmAudioBufIO_t* iop = _cmBa.devArray[ opp->devIdx ].ioArray + kOutIdx;
  168. // calc the number of requested bytes
  169. unsigned pktBufByteCnt = opp->chCnt * opp->audioFramesCnt * (bitsPerSample/8);
  170. // locate the oldest sub-buf which matches the pkt begin channel index
  171. cmAudioBufSubBuf_t* sbp = NULL;
  172. cmAudioBufSubBuf_t* tsbp = iop->subBufArray;
  173. for(j=0; j<iop->subBufCnt; ++j,++tsbp)
  174. if( tsbp->fullFl && (tsbp->pkt.begChIdx == opp->pkt.begChIdx) )
  175. if( sbp==NULL || tsbp->seqId < sbp->seqId )
  176. sbp = tsbp;
  177. if( sbp == NULL )
  178. {
  179. ++opp->faultCnt;
  180. rc = cmErrMsg(&_cmBa.err,kBufOverrunBaRC,"Output buffer underrun.");
  181. // zero the pkt buffer
  182. memset(opp->audioBytePtr,0,pktBufByteCnt);
  183. }
  184. else
  185. {
  186. // the channel count assoc'd with a given begin channel index should always match
  187. assert( sbp->pkt.chCnt == opp->chCnt );
  188. // we guarantee that the sample word width will always match
  189. assert( sbp->pkt.bitsPerSample == opp->bitsPerSample);
  190. // we don't want to deal with the case where the requested number of samples
  191. // is less than the number available from a single stored buffer - this would
  192. // require sending out a partial buffer
  193. assert( opp->audioFrameCnt >= sbp->pkt.audioFrameCnt );
  194. // calc the number of bytes to copy out
  195. unsigned bufByteCnt = sbp->pkt.chCnt * sbp->pkt.audioFramesCnt * (sbp->pkt.bitsPerSample/8);
  196. assert(bufByteCnt <= pktBufByteCnt );
  197. // copy out the requested samples
  198. memcpy(opp->audioBytesPtr,sbp->buf,cmMin(bufByteCnt,pktBufByteCnt));
  199. opp->audioFramesCnt = sbp->pkt.audioFramesCnt;
  200. // mark the sub-buffer as available
  201. sbp->fullFl = false;
  202. iop->fullCnt -= 1;;
  203. }
  204. }
  205. returnr c;
  206. }
  207. bool cmAudioBufIsDeviceReady( unsigned devIdx, unsigned flags )
  208. {
  209. unsigned i;
  210. assert( devIdx < _cmBa.devCnt );
  211. //
  212. if( cmIsFlag(flags,kInBaFl) )
  213. if( _cmBa.devArray[devIdx].ioArray[kInIdx].fullCnt==0)
  214. return false;
  215. if( cmIsFlag(flags,kOutBaFl) )
  216. if( _cmBa.devArray[devIdx].ioArray[kOutIdx].fullCnt == _cmBa.devArray[devIdx].ioArray[kOutIdx].subBufCnt )
  217. return false;
  218. return true;
  219. }
  220. cmBaRC_t cmAudioBufGet(
  221. unsigned devIdx,
  222. unsigned flags,
  223. cmApAudioPacket_t* pktArray[],
  224. unsigned pktCnt )
  225. {
  226. }
  227. cmBaRC_t cmAudioBufAdvance( unsigned devIdx, unsigned flags )
  228. {
  229. }