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

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