libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmAudioNrtDev.c 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #include "cmGlobal.h"
  2. #include "cmFloatTypes.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 "cmAudioNrtDev.h"
  10. #include "cmThread.h"
  11. enum
  12. {
  13. kStartedApNrtFl = 0x01,
  14. kInStateApNrtFl = 0x02
  15. };
  16. typedef struct
  17. {
  18. unsigned phase;
  19. bool implFl;
  20. double gain;
  21. } cmApNrtCh_t;
  22. typedef struct cmApNrtDev_str
  23. {
  24. unsigned flags;
  25. unsigned devIdx; // nrt device index
  26. unsigned baseApDevIdx; // global audio device index for first nrt device
  27. cmChar_t* label;
  28. unsigned iChCnt;
  29. unsigned oChCnt;
  30. double srate;
  31. unsigned fpc;
  32. cmThreadH_t thH;
  33. cmApCallbackPtr_t cbPtr;
  34. void* cbArg;
  35. unsigned cbPeriodMs;
  36. struct cmApNrtDev_str* link;
  37. unsigned curTimeSmp;
  38. cmApNrtCh_t* iChArray;
  39. cmApNrtCh_t* oChArray;
  40. } cmApNrtDev_t;
  41. typedef struct
  42. {
  43. cmErr_t err;
  44. unsigned devCnt;
  45. cmApNrtDev_t* devs;
  46. unsigned baseApDevIdx;
  47. } cmApNrt_t;
  48. cmApNrt_t* _cmNrt = NULL;
  49. cmApNrtDev_t* _cmApNrtIndexToDev( unsigned idx )
  50. {
  51. cmApNrtDev_t* dp = _cmNrt->devs;
  52. unsigned i;
  53. for(i=0; dp!=NULL && i<idx; ++i)
  54. dp = dp->link;
  55. assert( dp != NULL );
  56. return dp;
  57. }
  58. void cmApNrtGenImpulseCh( cmApNrtDev_t* dp, unsigned chIdx, cmSample_t* buf, unsigned chCnt, unsigned frmCnt )
  59. {
  60. double periodMs = 500; // impulse period
  61. double durMs = 50; // impulse length
  62. double loDb = -90.0;
  63. double hiDb = -20.0;
  64. double loLin = pow(10.0,loDb/20.0);
  65. double hiLin = pow(10.0,hiDb/20.0);
  66. unsigned periodSmp = (unsigned)(periodMs * dp->srate / 1000.0);
  67. unsigned durSmp = (unsigned)( durMs * dp->srate / 1000.0);
  68. assert( chIdx < chCnt );
  69. cmApNrtCh_t* cp = dp->iChArray + chIdx;
  70. cmSample_t* sp = buf + chIdx;
  71. unsigned i;
  72. for(i=0; i<frmCnt; ++i, sp+=chCnt )
  73. {
  74. unsigned limit = periodSmp;
  75. double gain = loLin;
  76. cp->phase += 1;
  77. if( cp->implFl )
  78. {
  79. gain = cp->gain;
  80. limit = durSmp;
  81. }
  82. *sp = (gain * 2.0 * rand()/RAND_MAX) - 1.0;
  83. if( cp->phase > limit )
  84. {
  85. cp->phase = 0;
  86. cp->implFl = !cp->implFl;
  87. if( cp->implFl )
  88. cp->gain = loLin + (hiLin - loLin) * rand()/RAND_MAX ;
  89. }
  90. }
  91. }
  92. void cmApNrtGenImpulse( cmApNrtDev_t* dp, cmSample_t* buf, unsigned chCnt, unsigned frmCnt )
  93. {
  94. unsigned i=0;
  95. for(; i<chCnt; ++i)
  96. cmApNrtGenImpulseCh(dp,i,buf,chCnt,frmCnt);
  97. }
  98. void cmApNrtGenSamples( cmApNrtDev_t* dp, cmSample_t* buf, unsigned chCnt, unsigned frmCnt )
  99. {
  100. memset(buf,0,chCnt*frmCnt*sizeof(cmSample_t));
  101. cmApNrtGenImpulse(dp,buf,chCnt,frmCnt);
  102. dp->curTimeSmp += frmCnt;
  103. }
  104. // return 'false' to terminate otherwise return 'true'.
  105. bool cmApNrtThreadFunc(void* param)
  106. {
  107. cmApNrtDev_t* dp = (cmApNrtDev_t*)param;
  108. cmSleepUs( dp->cbPeriodMs * 1000 );
  109. cmApAudioPacket_t pkt;
  110. bool inFl = cmIsFlag(dp->flags,kInStateApNrtFl);
  111. pkt.devIdx = dp->devIdx + dp->baseApDevIdx;
  112. pkt.begChIdx = 0;
  113. pkt.audioFramesCnt = dp->fpc;
  114. pkt.bitsPerSample = 32;
  115. pkt.flags = kInterleavedApFl | kFloatApFl;
  116. pkt.userCbPtr = dp->cbArg;
  117. if( inFl )
  118. {
  119. unsigned bn = dp->iChCnt * dp->fpc;
  120. cmSample_t b[ bn ];
  121. pkt.chCnt = dp->iChCnt;
  122. pkt.audioBytesPtr = b;
  123. cmApNrtGenSamples(dp,b,dp->iChCnt,dp->fpc);
  124. dp->cbPtr(&pkt,1,NULL,0 ); // send the samples to the application
  125. }
  126. else
  127. {
  128. unsigned bn = dp->oChCnt * dp->fpc;
  129. cmSample_t b[ bn ];
  130. pkt.chCnt = dp->oChCnt;
  131. pkt.audioBytesPtr = b;
  132. dp->cbPtr(NULL,0,&pkt,1 ); // recv the samples from the application
  133. }
  134. dp->flags = cmTogFlag(dp->flags,kInStateApNrtFl);
  135. return true;
  136. }
  137. cmApRC_t cmApNrtAllocate( cmRpt_t* rpt )
  138. {
  139. if( _cmNrt != NULL )
  140. cmApNrtFree();
  141. _cmNrt = cmMemAllocZ(cmApNrt_t,1);
  142. cmErrSetup(&_cmNrt->err,rpt,"cmAudioNrtDev");
  143. _cmNrt->devCnt = 0;
  144. _cmNrt->devs = NULL;
  145. _cmNrt->baseApDevIdx = 0;
  146. return kOkApRC;
  147. }
  148. cmApRC_t cmApNrtFree()
  149. {
  150. cmApRC_t rc = kOkApRC;
  151. cmApNrtDev_t* dp = _cmNrt->devs;
  152. while( dp != NULL )
  153. {
  154. cmApNrtDev_t* np = dp->link;
  155. if( cmThreadIsValid(dp->thH) )
  156. if( cmThreadDestroy(&dp->thH) != kOkThRC )
  157. rc = cmErrMsg(&_cmNrt->err,kThreadFailApRC,"Thread destroy failed.");
  158. cmMemFree(dp->label);
  159. cmMemFree(dp->iChArray);
  160. cmMemFree(dp->oChArray);
  161. cmMemFree(dp);
  162. dp = np;
  163. }
  164. if( rc == kOkApRC )
  165. {
  166. cmMemPtrFree(&_cmNrt);
  167. }
  168. return rc;
  169. }
  170. cmApRC_t cmApNrtCreateDevice(
  171. const cmChar_t* label,
  172. double srate,
  173. unsigned iChCnt,
  174. unsigned oChCnt,
  175. unsigned cbPeriodMs )
  176. {
  177. cmApRC_t rc = kOkApRC;
  178. cmApNrtDev_t* dp = cmMemAllocZ(cmApNrtDev_t,1);
  179. dp->devIdx = _cmNrt->devCnt;
  180. dp->baseApDevIdx = _cmNrt->baseApDevIdx;
  181. dp->label = cmMemAllocStr(label);
  182. dp->iChCnt = iChCnt;
  183. dp->oChCnt = oChCnt;
  184. dp->srate = srate;
  185. dp->fpc = 0;
  186. dp->cbPeriodMs = cbPeriodMs;
  187. dp->cbPtr = NULL;
  188. dp->cbArg = NULL;
  189. dp->link = NULL;
  190. dp->iChArray = iChCnt==0 ? NULL : cmMemAllocZ(cmApNrtCh_t,iChCnt);
  191. dp->oChArray = oChCnt==0 ? NULL : cmMemAllocZ(cmApNrtCh_t,oChCnt);
  192. // attach the new recd to the end of the list
  193. cmApNrtDev_t* np = _cmNrt->devs;
  194. while( np != NULL && np->link != NULL )
  195. np = np->link;
  196. if( np == NULL )
  197. _cmNrt->devs = dp;
  198. else
  199. np->link = dp;
  200. if( cmThreadCreate( &dp->thH, cmApNrtThreadFunc, dp, _cmNrt->err.rpt ) != kOkThRC )
  201. rc = cmErrMsg(&_cmNrt->err,kThreadFailApRC,"Thread create failed.");
  202. ++_cmNrt->devCnt;
  203. return rc;
  204. }
  205. cmApRC_t cmApNrtInitialize( cmRpt_t* rpt, unsigned baseApDevIdx )
  206. {
  207. // set the baseApDevIdx for each device
  208. cmApNrtDev_t* dp = _cmNrt->devs;
  209. for(; dp!=NULL; dp=dp->link)
  210. dp->baseApDevIdx = baseApDevIdx;
  211. // store the baseApDevIdx for any devices that may be created after initialization
  212. _cmNrt->baseApDevIdx = baseApDevIdx;
  213. return kOkApRC;
  214. }
  215. cmApRC_t cmApNrtFinalize()
  216. {
  217. return kOkApRC;
  218. }
  219. unsigned cmApNrtDeviceCount()
  220. { return _cmNrt==NULL ? 0 : _cmNrt->devCnt; }
  221. const char* cmApNrtDeviceLabel( unsigned devIdx )
  222. {
  223. assert( devIdx < _cmNrt->devCnt );
  224. const cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  225. return dp->label;
  226. }
  227. unsigned cmApNrtDeviceChannelCount( unsigned devIdx, bool inputFl )
  228. {
  229. assert( devIdx < _cmNrt->devCnt );
  230. const cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  231. return inputFl ? dp->iChCnt : dp->oChCnt;
  232. }
  233. double cmApNrtDeviceSampleRate( unsigned devIdx )
  234. {
  235. assert( devIdx < _cmNrt->devCnt );
  236. const cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  237. return dp->srate;
  238. }
  239. unsigned cmApNrtDeviceFramesPerCycle( unsigned devIdx, bool inputFl )
  240. {
  241. assert( devIdx < _cmNrt->devCnt );
  242. const cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  243. return dp->fpc;
  244. }
  245. cmApRC_t cmApNrtDeviceSetup(
  246. unsigned devIdx,
  247. double srate,
  248. unsigned framesPerCycle,
  249. cmApCallbackPtr_t callbackPtr,
  250. void* userCbPtr )
  251. {
  252. assert( devIdx < _cmNrt->devCnt );
  253. cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  254. dp->srate = srate;
  255. dp->fpc = framesPerCycle;
  256. dp->cbPtr = callbackPtr;
  257. dp->cbArg = userCbPtr;
  258. return kOkApRC;
  259. }
  260. cmApRC_t cmApNrtDeviceStart( unsigned devIdx )
  261. {
  262. assert( devIdx < _cmNrt->devCnt );
  263. cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  264. dp->curTimeSmp = 0;
  265. if( cmThreadPause( dp->thH, 0 ) != kOkThRC )
  266. return cmErrMsg(&_cmNrt->err,kThreadFailApRC,"Thread start failed.");
  267. dp->flags = cmSetFlag(dp->flags,kStartedApNrtFl);
  268. return kOkApRC;
  269. }
  270. cmApRC_t cmApNrtDeviceStop( unsigned devIdx )
  271. {
  272. assert( devIdx < _cmNrt->devCnt );
  273. cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  274. if( cmThreadPause( dp->thH, kPauseThFl ) != kOkThRC )
  275. return cmErrMsg(&_cmNrt->err,kThreadFailApRC,"Thread pause failed.");
  276. dp->flags = cmClrFlag(dp->flags,kStartedApNrtFl);
  277. return kOkApRC;
  278. }
  279. bool cmApNrtDeviceIsStarted( unsigned devIdx )
  280. {
  281. assert( devIdx < _cmNrt->devCnt );
  282. const cmApNrtDev_t* dp = _cmApNrtIndexToDev(devIdx);
  283. return cmIsFlag(dp->flags,kStartedApNrtFl);
  284. }