cmtools is a collection of utilities for generating and processing machine readable musical scores based on MusicXML, MIDI and other data files.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmFileSys.h"
  10. #include "cmText.h"
  11. #include "cmPgmOpts.h"
  12. #include "cmTime.h"
  13. #include "cmAudioPort.h"
  14. #include "cmApBuf.h" // only needed for cmApBufTest().
  15. #include "cmAudioPortFile.h"
  16. #include "cmAudioAggDev.h"
  17. #include "cmAudioNrtDev.h"
  18. #include "cmFloatTypes.h"
  19. #include "cmAudioFile.h"
  20. #include "cmFile.h"
  21. enum
  22. {
  23. kOkAdRC = cmOkRC,
  24. kAudioPortFailAdRC,
  25. kAudioPortFileFailAdRC,
  26. kAudioPortNrtFailAdRC,
  27. kAudioBufFailAdRC
  28. };
  29. const cmChar_t* poBegHelpStr =
  30. "audiodev Test the real-time audio ports"
  31. "\n"
  32. "audiodev -i<in_dev_index> -o <out_dev_index -s <sample_rate>\n"
  33. "\n"
  34. "All arguments are optional. The default input and output device index is 0.\n"
  35. "\n";
  36. const cmChar_t* poEndHelpStr = "";
  37. /// [cmAudioPortExample]
  38. // See cmApPortTest() below for the main point of entry.
  39. // Data structure used to hold the parameters for cpApPortTest()
  40. // and the user defined data record passed to the host from the
  41. // audio port callback functions.
  42. typedef struct
  43. {
  44. unsigned bufCnt; // 2=double buffering 3=triple buffering
  45. unsigned chIdx; // first test channel
  46. unsigned chCnt; // count of channels to test
  47. unsigned framesPerCycle; // DSP frames per cycle
  48. unsigned bufFrmCnt; // count of DSP frames used by the audio buffer (bufCnt * framesPerCycle)
  49. unsigned bufSmpCnt; // count of samples used by the audio buffer (chCnt * bufFrmCnt)
  50. unsigned inDevIdx; // input device index
  51. unsigned outDevIdx; // output device index
  52. double srate; // audio sample rate
  53. unsigned meterMs; // audio meter buffer length
  54. // param's and state for cmApSynthSine()
  55. unsigned phase; // sine synth phase
  56. double frqHz; // sine synth frequency in Hz
  57. // buffer and state for cmApCopyIn/Out()
  58. cmApSample_t* buf; // buf[bufSmpCnt] - circular interleaved audio buffer
  59. unsigned bufInIdx; // next input buffer index
  60. unsigned bufOutIdx; // next output buffer index
  61. unsigned bufFullCnt; // count of full samples
  62. // debugging log data arrays
  63. unsigned logCnt; // count of elements in log[] and ilong[]
  64. char* log; // log[logCnt]
  65. unsigned* ilog; // ilog[logCnt]
  66. unsigned logIdx; // current log index
  67. unsigned cbCnt; // count the callback
  68. } cmApPortTestRecd;
  69. unsigned _cmGlobalInDevIdx = 0;
  70. unsigned _cmGlobalOutDevIdx = 0;
  71. unsigned _cmGlobalCbCnt = 0;
  72. #define aSrate 48000
  73. #define aFrmN aSrate*10
  74. #define aChN 2
  75. #define abufN aFrmN*aChN
  76. cmApSample_t abuf[ abufN ];
  77. unsigned abufi = 0;
  78. void _abuf_copy_in( cmApAudioPacket_t* pktArray, unsigned pktN )
  79. {
  80. unsigned i,j,k;
  81. for(i=0; i<pktN; ++i)
  82. {
  83. cmApSample_t* sp = (cmApSample_t*)(pktArray[i].audioBytesPtr);
  84. unsigned frmN = pktArray[i].audioFramesCnt;
  85. unsigned chN = cmMin(pktArray[i].chCnt,aChN);
  86. for(j=0; abufi<aFrmN && j<frmN; ++j, ++abufi)
  87. for(k=0; k<chN; ++k)
  88. abuf[ (k*aFrmN) + abufi ] = *sp++;
  89. }
  90. }
  91. void _abuf_write_audio_file(cmCtx_t* ctx )
  92. {
  93. cmApSample_t* sigVV[ ] = { abuf, abuf + aFrmN };
  94. cmAudioFileWriteFileFloat( "/home/kevin/temp/temp.wav", aSrate, 16, aFrmN, 2, sigVV, &ctx->rpt );
  95. }
  96. void _abuf_write_csv_file(cmCtx_t* ctx )
  97. {
  98. cmFileH_t fH = cmFileNullHandle;
  99. unsigned i = 0,j;
  100. cmFileOpen( &fH, "/home/kevin/temp/temp.csv", kWriteFileFl, &ctx->rpt );
  101. for(i=0; i<aFrmN; ++i)
  102. {
  103. for(j=0; j<aChN; ++j)
  104. {
  105. char comma = j==aChN-1 ? ' ':',';
  106. cmFilePrintf(fH, "%f%c",abuf[ aFrmN*j + i ], comma );
  107. }
  108. cmFilePrintf( fH, "\n");
  109. }
  110. cmFileClose(&fH);
  111. }
  112. void _cmApPortCb2( cmApAudioPacket_t* inPktArray, unsigned inPktCnt, cmApAudioPacket_t* outPktArray, unsigned outPktCnt )
  113. {
  114. cmApBufInputToOutput( _cmGlobalInDevIdx, _cmGlobalOutDevIdx );
  115. cmApBufUpdate( inPktArray, inPktCnt, outPktArray, outPktCnt );
  116. if( outPktArray != NULL )
  117. _abuf_copy_in(outPktArray,outPktCnt);
  118. _cmGlobalCbCnt += 1;
  119. }
  120. cmRC_t audio_port_test( cmCtx_t* ctx, cmApPortTestRecd* r, bool runFl )
  121. {
  122. cmRC_t rc = kOkAdRC;
  123. unsigned i = 0;
  124. int srateMult = 0;
  125. cmRpt_t* rpt = &ctx->rpt;
  126. cmApSample_t buf[r->bufSmpCnt];
  127. char log[r->logCnt];
  128. unsigned ilog[r->logCnt];
  129. r->buf = buf;
  130. r->log = log;
  131. r->ilog = ilog;
  132. r->cbCnt = 0;
  133. _cmGlobalInDevIdx = r->inDevIdx;
  134. _cmGlobalOutDevIdx= r->outDevIdx;
  135. cmRptPrintf(rpt,"%s in:%i out:%i chidx:%i chs:%i bufs=%i frm=%i rate=%f\n",runFl?"exec":"rpt",r->inDevIdx,r->outDevIdx,r->chIdx,r->chCnt,r->bufCnt,r->framesPerCycle,r->srate);
  136. if( cmApFileAllocate(rpt) != kOkApRC )
  137. {
  138. rc = cmErrMsg(&ctx->err, kAudioPortFileFailAdRC,"Audio port file allocation failed.");
  139. goto errLabel;
  140. }
  141. // allocate the non-real-time port
  142. if( cmApNrtAllocate(rpt) != kOkApRC )
  143. {
  144. rc = cmErrMsg(&ctx->err, kAudioPortNrtFailAdRC,"Non-real-time system allocation failed.");
  145. goto errLabel;
  146. }
  147. // initialize the audio device interface
  148. if( cmApInitialize(rpt) != kOkApRC )
  149. {
  150. rc = cmErrMsg(&ctx->err, kAudioPortFailAdRC,"Port initialize failed.\n");
  151. goto errLabel;
  152. }
  153. // report the current audio device configuration
  154. for(i=0; i<cmApDeviceCount(); ++i)
  155. {
  156. cmRptPrintf(rpt,"%i [in: chs=%i frames=%i] [out: chs=%i frames=%i] srate:%f %s\n",i,cmApDeviceChannelCount(i,true),cmApDeviceFramesPerCycle(i,true),cmApDeviceChannelCount(i,false),cmApDeviceFramesPerCycle(i,false),cmApDeviceSampleRate(i),cmApDeviceLabel(i));
  157. }
  158. // report the current audio devices using the audio port interface function
  159. cmApReport(rpt);
  160. if( runFl )
  161. {
  162. // initialize the audio buffer
  163. cmApBufInitialize( cmApDeviceCount(), r->meterMs );
  164. // setup the buffer for the output device
  165. cmApBufSetup( r->outDevIdx, r->srate, r->framesPerCycle, r->bufCnt, cmApDeviceChannelCount(r->outDevIdx,true), r->framesPerCycle, cmApDeviceChannelCount(r->outDevIdx,false), r->framesPerCycle, srateMult );
  166. // setup the buffer for the input device
  167. if( r->inDevIdx != r->outDevIdx )
  168. cmApBufSetup( r->inDevIdx, r->srate, r->framesPerCycle, r->bufCnt, cmApDeviceChannelCount(r->inDevIdx,true), r->framesPerCycle, cmApDeviceChannelCount(r->inDevIdx,false), r->framesPerCycle, srateMult );
  169. // setup an output device
  170. if(cmApDeviceSetup(r->outDevIdx,r->srate,r->framesPerCycle,_cmApPortCb2,&r) != kOkApRC )
  171. rc = cmErrMsg(&ctx->err,kAudioPortFailAdRC,"Out audio device setup failed.\n");
  172. else
  173. // setup an input device
  174. if( cmApDeviceSetup(r->inDevIdx,r->srate,r->framesPerCycle,_cmApPortCb2,&r) != kOkApRC )
  175. rc = cmErrMsg(&ctx->err,kAudioPortFailAdRC,"In audio device setup failed.\n");
  176. else
  177. // start the input device
  178. if( cmApDeviceStart(r->inDevIdx) != kOkApRC )
  179. rc = cmErrMsg(&ctx->err,kAudioPortFailAdRC,"In audio device start failed.\n");
  180. else
  181. // start the output device
  182. if( cmApDeviceStart(r->outDevIdx) != kOkApRC )
  183. rc = cmErrMsg(&ctx->err, kAudioPortFailAdRC,"Out audio device start failed.\n");
  184. else
  185. cmRptPrintf(rpt,"Started...");
  186. cmApBufEnableChannel(r->inDevIdx, -1, kEnableApFl | kInApFl );
  187. cmApBufEnableMeter( r->inDevIdx, -1, kEnableApFl | kInApFl );
  188. cmApBufEnableChannel(r->outDevIdx, -1, kEnableApFl | kOutApFl );
  189. cmApBufEnableMeter( r->outDevIdx, -1, kEnableApFl | kOutApFl );
  190. cmRptPrintf(rpt,"q=quit O/o=output tone, I/i=input tone P/p=pass s=buf report\n");
  191. char c;
  192. while((c=getchar()) != 'q')
  193. {
  194. //cmApAlsaDeviceRtReport(rpt,r->outDevIdx);
  195. switch(c)
  196. {
  197. case 'i':
  198. case 'I':
  199. cmApBufEnableTone(r->inDevIdx,-1,kInApFl | (c=='I'?kEnableApFl:0));
  200. break;
  201. case 'o':
  202. case 'O':
  203. cmApBufEnableTone(r->outDevIdx,-1,kOutApFl | (c=='O'?kEnableApFl:0));
  204. break;
  205. case 'p':
  206. case 'P':
  207. cmApBufEnablePass(r->outDevIdx,-1,kOutApFl | (c=='P'?kEnableApFl:0));
  208. break;
  209. case 's':
  210. cmApBufReport(rpt);
  211. cmRptPrintf(rpt,"CB:%i\n",_cmGlobalCbCnt);
  212. break;
  213. }
  214. }
  215. // stop the input device
  216. if( cmApDeviceIsStarted(r->inDevIdx) )
  217. if( cmApDeviceStop(r->inDevIdx) != kOkApRC )
  218. cmRptPrintf(rpt,"In device stop failed.\n");
  219. // stop the output device
  220. if( cmApDeviceIsStarted(r->outDevIdx) )
  221. if( cmApDeviceStop(r->outDevIdx) != kOkApRC )
  222. cmRptPrintf(rpt,"Out device stop failed.\n");
  223. }
  224. errLabel:
  225. // release any resources held by the audio port interface
  226. if( cmApFinalize() != kOkApRC )
  227. rc = cmErrMsg(&ctx->err,kAudioPortFailAdRC,"Finalize failed.\n");
  228. cmApBufFinalize();
  229. cmApNrtFree();
  230. cmApFileFree();
  231. // report the count of audio buffer callbacks
  232. cmRptPrintf(rpt,"cb count:%i\n", r->cbCnt );
  233. //for(i=0; i<_logCnt; ++i)
  234. // cmRptPrintf(rpt,"%c(%i)",_log[i],_ilog[i]);
  235. //cmRptPrintf(rpt,"\n");
  236. return rc;
  237. }
  238. void print( void* arg, const char* text )
  239. {
  240. printf("%s",text);
  241. }
  242. int main( int argc, char* argv[] )
  243. {
  244. enum
  245. {
  246. kSratePoId = kBasePoId,
  247. kHzPoId,
  248. kChIdxPoId,
  249. kChCntPoId,
  250. kBufCntPoId,
  251. kFrmCntPoId,
  252. kFrmsPerBufPoId,
  253. kInDevIdxPoId,
  254. kOutDevIdxPoId,
  255. kReportFlagPoId
  256. };
  257. cmRC_t rc = cmOkRC;
  258. bool memDebugFl = cmDEBUG_FL;
  259. unsigned memGuardByteCnt = memDebugFl ? 8 : 0;
  260. unsigned memAlignByteCnt = 16;
  261. unsigned memFlags = memDebugFl ? kTrackMmFl | kDeferFreeMmFl | kFillUninitMmFl : 0;
  262. cmPgmOptH_t poH = cmPgmOptNullHandle;
  263. const cmChar_t* appTitle = "audiodev";
  264. unsigned reportFl = 0;
  265. cmCtx_t ctx;
  266. cmApPortTestRecd r;
  267. memset(&r,0,sizeof(r));
  268. r.meterMs = 50;
  269. r.logCnt = 100;
  270. memset(abuf,0,sizeof(cmApSample_t)*abufN);
  271. cmCtxSetup(&ctx,appTitle,print,print,NULL,memGuardByteCnt,memAlignByteCnt,memFlags);
  272. cmMdInitialize( memGuardByteCnt, memAlignByteCnt, memFlags, &ctx.rpt );
  273. cmFsInitialize( &ctx, appTitle );
  274. cmTsInitialize(&ctx );
  275. cmPgmOptInitialize(&ctx, &poH, poBegHelpStr, poEndHelpStr );
  276. cmPgmOptInstallDbl( poH, kSratePoId, 's', "srate", 0, 48000, &r.srate, 1,
  277. "Audio system sample rate." );
  278. cmPgmOptInstallDbl( poH, kHzPoId, 'z', "hz", 0, 1000, &r.frqHz, 1,
  279. "Tone frequency in Hertz." );
  280. cmPgmOptInstallUInt( poH, kChIdxPoId, 'x', "ch_index", 0, 0, &r.chIdx, 1,
  281. "Index of first channel index." );
  282. cmPgmOptInstallUInt( poH, kChCntPoId, 'c', "ch_cnt", 0, 2, &r.chCnt, 1,
  283. "Count of audio channels." );
  284. cmPgmOptInstallUInt( poH, kBufCntPoId, 'b', "buf_cnt", 0, 3, &r.bufCnt, 1,
  285. "Count of audio buffers. (e.g. 2=double buffering, 3=triple buffering)" );
  286. cmPgmOptInstallUInt( poH, kFrmsPerBufPoId, 'f', "frames_per_buf",0, 512, &r.framesPerCycle, 1,
  287. "Count of audio channels." );
  288. cmPgmOptInstallUInt( poH, kInDevIdxPoId, 'i', "in_dev_index",0, 0, &r.inDevIdx, 1,
  289. "Input device index as taken from the audio device report." );
  290. cmPgmOptInstallUInt( poH, kOutDevIdxPoId, 'o', "out_dev_index",0, 0, &r.outDevIdx, 1,
  291. "Output device index as taken from the audio device report." );
  292. cmPgmOptInstallFlag( poH, kReportFlagPoId, 'r', "report_flag", 0, 1, &reportFl, 1,
  293. "Print an audio device report." );
  294. // parse the command line arguments
  295. if( cmPgmOptParse(poH, argc, argv ) == kOkPoRC )
  296. {
  297. // handle the built-in arg's (e.g. -v,-p,-h)
  298. // (returns false if only built-in options were selected)
  299. if( cmPgmOptHandleBuiltInActions(poH, &ctx.rpt ) == false )
  300. goto errLabel;
  301. rc = audio_port_test( &ctx, &r, !reportFl );
  302. }
  303. errLabel:
  304. _abuf_write_audio_file(&ctx);
  305. cmPgmOptFinalize(&poH);
  306. cmTsFinalize();
  307. cmFsFinalize();
  308. cmMdReport( kIgnoreNormalMmFl );
  309. cmMdFinalize();
  310. return rc;
  311. }