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