cmtools is a collection of utilities for generating and processing machine readable musical scores based on MusicXML, MIDI and other data files.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

audiodev.c 12KB

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