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

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