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.

cmAudioNrtDev.c 8.3KB

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