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

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