libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. }