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.9KB

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