libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmAudioPortFile.c 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmTime.h"
  10. #include "cmAudioPort.h"
  11. #include "cmAudioPortFile.h"
  12. #include "cmAudioFileDev.h"
  13. typedef struct
  14. {
  15. cmAfdH_t devH;
  16. unsigned devIdx; // afp dev idx
  17. unsigned baseApDevIdx; // global audio device index for first afp device
  18. } cmApDev_t;
  19. typedef struct
  20. {
  21. cmErr_t err;
  22. cmApDev_t* devArray;
  23. unsigned devCnt;
  24. unsigned baseApDevIdx;
  25. } cmApf_t;
  26. cmApf_t* _cmApf = NULL;
  27. cmApRC_t cmApFileAllocate( cmRpt_t* rpt )
  28. {
  29. cmApRC_t rc = kOkApRC;
  30. if( _cmApf != NULL )
  31. cmApFileFree();
  32. _cmApf = cmMemAllocZ(cmApf_t,1);
  33. cmErrSetup(&_cmApf->err,rpt,"Audio Port File");
  34. _cmApf->devArray = NULL;
  35. _cmApf->devCnt = 0;
  36. _cmApf->baseApDevIdx = 0;
  37. return rc;
  38. }
  39. cmApRC_t cmApFileFree()
  40. {
  41. cmApRC_t rc = kOkApRC;
  42. if( _cmApf == NULL )
  43. return rc;
  44. if((rc = cmApFileFinalize()) != kOkApRC )
  45. return rc;
  46. cmMemFree(_cmApf);
  47. _cmApf = NULL;
  48. return rc;
  49. }
  50. cmApRC_t cmApFileInitialize( cmRpt_t* rpt, unsigned baseApDevIdx )
  51. {
  52. cmApRC_t rc = kOkApRC;
  53. unsigned i = 0;
  54. for(; i<_cmApf->devCnt; ++i)
  55. _cmApf->devArray[i].baseApDevIdx = baseApDevIdx;
  56. _cmApf->baseApDevIdx = baseApDevIdx;
  57. return rc;
  58. }
  59. cmApRC_t cmApFileFinalize()
  60. {
  61. cmApRC_t rc = kOkApRC;
  62. if( _cmApf == NULL )
  63. return kOkApRC;
  64. unsigned i;
  65. for(i=0; i<_cmApf->devCnt; ++i)
  66. {
  67. cmApRC_t rc0;
  68. if((rc0 = cmApFileDeviceDestroy(i)) != kOkApRC )
  69. rc = rc0;
  70. }
  71. cmMemPtrFree(&_cmApf->devArray);
  72. _cmApf->devCnt = 0;
  73. cmMemPtrFree(&_cmApf);
  74. return rc;
  75. }
  76. unsigned cmApFileDeviceCreate(
  77. const cmChar_t* devLabel,
  78. const cmChar_t* iFn,
  79. const cmChar_t* oFn,
  80. unsigned oBits,
  81. unsigned oChCnt )
  82. {
  83. unsigned i;
  84. // find an available device slot
  85. for(i=0; i<_cmApf->devCnt; ++i)
  86. if( cmAudioFileDevIsValid( _cmApf->devArray[i].devH ) == false )
  87. break;
  88. // if no device slot is availd ...
  89. if( i == _cmApf->devCnt )
  90. {
  91. // ... create a new one
  92. _cmApf->devArray = cmMemResizePZ(cmApDev_t, _cmApf->devArray, _cmApf->devCnt+1);
  93. ++_cmApf->devCnt;
  94. }
  95. // open the file device
  96. if( cmAudioFileDevInitialize( &_cmApf->devArray[i].devH, devLabel, i, iFn, oFn, oBits, oChCnt, _cmApf->err.rpt ) != kOkAfdRC )
  97. {
  98. cmErrMsg(&_cmApf->err,kAudioPortFileFailApRC,"The audio file device initialization failed.");
  99. i = cmInvalidIdx;
  100. goto errLabel;
  101. }
  102. _cmApf->devArray[i].devIdx = i;
  103. errLabel:
  104. return i;
  105. }
  106. cmApRC_t cmApFileDeviceDestroy( unsigned devIdx )
  107. {
  108. if( cmAudioFileDevFinalize( &_cmApf->devArray[devIdx].devH ) != kOkAfdRC )
  109. return cmErrMsg(&_cmApf->err,kAudioPortFileFailApRC,"The audio file device finalize failed.");
  110. return kOkApRC;
  111. }
  112. unsigned cmApFileDeviceCount()
  113. { return _cmApf->devCnt; }
  114. const char* cmApFileDeviceLabel( unsigned devIdx )
  115. {
  116. assert( devIdx < cmApFileDeviceCount());
  117. return cmAudioFileDevLabel( _cmApf->devArray[devIdx].devH );
  118. }
  119. unsigned cmApFileDeviceChannelCount( unsigned devIdx, bool inputFl )
  120. {
  121. assert( devIdx < cmApFileDeviceCount());
  122. return cmAudioFileDevChannelCount( _cmApf->devArray[devIdx].devH, inputFl );
  123. }
  124. double cmApFileDeviceSampleRate( unsigned devIdx )
  125. {
  126. assert( devIdx < cmApFileDeviceCount());
  127. return cmAudioFileDevSampleRate( _cmApf->devArray[devIdx].devH );
  128. }
  129. unsigned cmApFileDeviceFramesPerCycle( unsigned devIdx, bool inputFl )
  130. {
  131. assert( devIdx < cmApFileDeviceCount());
  132. return cmAudioFileDevFramesPerCycle( _cmApf->devArray[devIdx].devH, inputFl );
  133. }
  134. cmApRC_t cmApFileDeviceSetup(
  135. unsigned devIdx,
  136. double srate,
  137. unsigned framesPerCycle,
  138. cmApCallbackPtr_t callbackPtr,
  139. void* userCbPtr )
  140. {
  141. assert( devIdx < cmApFileDeviceCount());
  142. if( cmAudioFileDevSetup( _cmApf->devArray[devIdx].devH,_cmApf->baseApDevIdx,srate,framesPerCycle,callbackPtr,userCbPtr) != kOkAfdRC )
  143. return cmErrMsg(&_cmApf->err,kAudioPortFileFailApRC,"The audio file device setup failed.");
  144. return kOkApRC;
  145. }
  146. cmApRC_t cmApFileDeviceStart( unsigned devIdx )
  147. {
  148. assert( devIdx < cmApFileDeviceCount());
  149. if( cmAudioFileDevStart( _cmApf->devArray[devIdx].devH ) != kOkAfdRC )
  150. return cmErrMsg(&_cmApf->err,kAudioPortFileFailApRC,"The audio file device setup failed.");
  151. return kOkApRC;
  152. }
  153. cmApRC_t cmApFileDeviceStop( unsigned devIdx )
  154. {
  155. assert( devIdx < cmApFileDeviceCount());
  156. if( cmAudioFileDevStop( _cmApf->devArray[devIdx].devH ) != kOkAfdRC )
  157. return cmErrMsg(&_cmApf->err,kAudioPortFileFailApRC,"The audio file device setup failed.");
  158. return kOkApRC;
  159. }
  160. bool cmApFileDeviceIsStarted( unsigned devIdx )
  161. {
  162. assert( devIdx < cmApFileDeviceCount());
  163. return cmAudioFileDevIsStarted( _cmApf->devArray[devIdx].devH );
  164. }
  165. void cmApFileReport( cmRpt_t* rpt )
  166. {
  167. unsigned i;
  168. for(i=0; _cmApf->devCnt; ++i)
  169. {
  170. cmRptPrintf(rpt,"%i: ",i);
  171. cmAudioFileDevReport( _cmApf->devArray[i].devH, rpt );
  172. cmRptPrintf(rpt,"\n");
  173. }
  174. }
  175. // device callback function used with cmAudioPortFileTest() note that this assumes
  176. // that the packet buffer contain non-interleaved data.
  177. void _cmApFileTestCb(
  178. cmApAudioPacket_t* inPktArray,
  179. unsigned inPktCnt,
  180. cmApAudioPacket_t* outPktArray,
  181. unsigned outPktCnt )
  182. {
  183. cmApAudioPacket_t* ip = inPktArray;
  184. cmApAudioPacket_t* op = outPktArray;
  185. unsigned opi = 0;
  186. unsigned ipi = 0;
  187. unsigned oci = 0;
  188. unsigned ici = 0;
  189. while(1)
  190. {
  191. if( ici == ip->chCnt)
  192. {
  193. ici = 0;
  194. if( ++ipi >= inPktCnt )
  195. break;
  196. ip = inPktArray + ipi;
  197. }
  198. if( oci == op->chCnt )
  199. {
  200. oci = 0;
  201. if( ++opi >= outPktCnt )
  202. break;
  203. ip = outPktArray + opi;
  204. }
  205. assert( ip->audioFramesCnt == op->audioFramesCnt );
  206. assert( cmIsFlag(ip->flags,kInterleavedApFl)==false && cmIsFlag(ip->flags,kInterleavedApFl)==false );
  207. cmApSample_t* ibp = ((cmApSample_t*)ip->audioBytesPtr) + (ip->audioFramesCnt*ici);
  208. cmApSample_t* obp = ((cmApSample_t*)op->audioBytesPtr) + (op->audioFramesCnt*oci);
  209. memcpy(obp,ibp,ip->audioFramesCnt*sizeof(cmApSample_t));
  210. ++ici;
  211. ++oci;
  212. }
  213. }
  214. void cmApFileTest( cmRpt_t* rpt )
  215. {
  216. unsigned dev0Idx;
  217. const cmChar_t* promptStr = "apf> q=quit 1=start 0=stop\n";
  218. const cmChar_t* label0 = "file0";
  219. const cmChar_t* i0Fn = "/home/kevin/media/audio/McGill-1/1 Audio Track.aiff";
  220. const cmChar_t* o0Fn = "/home/kevin/temp/afd1.aif";
  221. unsigned o0Bits = 16;
  222. unsigned o0ChCnt = 2;
  223. double srate = 44100;
  224. unsigned framesPerCycle = 512;
  225. // initialize audio port file API
  226. if( cmApFileInitialize(rpt,0) != kOkApRC )
  227. return;
  228. // create an audio port file
  229. if((dev0Idx = cmApFileDeviceCreate(label0,i0Fn,o0Fn,o0Bits,o0ChCnt)) == cmInvalidIdx )
  230. goto errLabel;
  231. // configure an audio port file
  232. if( cmApFileDeviceSetup( dev0Idx, srate, framesPerCycle, _cmApFileTestCb, NULL ) != kOkAfdRC )
  233. goto errLabel;
  234. char c;
  235. fputs(promptStr,stderr);
  236. fflush(stdin);
  237. while((c=getchar()) != 'q')
  238. {
  239. switch(c)
  240. {
  241. case '0': cmApFileDeviceStart(dev0Idx); break;
  242. case '1': cmApFileDeviceStop(dev0Idx); break;
  243. }
  244. fputs(promptStr,stderr);
  245. fflush(stdin);
  246. c = 0;
  247. }
  248. errLabel:
  249. //cmApFileDeviceDestroy(dev0Idx);
  250. cmApFileFinalize();
  251. }