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.

cmDspPgmPP.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  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 "cmFloatTypes.h"
  6. #include "cmRpt.h"
  7. #include "cmErr.h"
  8. #include "cmCtx.h"
  9. #include "cmMem.h"
  10. #include "cmMallocDebug.h"
  11. #include "cmLinkedHeap.h"
  12. #include "cmText.h"
  13. #include "cmFileSys.h"
  14. #include "cmSymTbl.h"
  15. #include "cmJson.h"
  16. #include "cmPrefs.h"
  17. #include "cmDspValue.h"
  18. #include "cmMsgProtocol.h"
  19. #include "cmThread.h"
  20. #include "cmUdpPort.h"
  21. #include "cmUdpNet.h"
  22. #include "cmSerialPort.h"
  23. #include "cmTime.h"
  24. #include "cmAudioSys.h"
  25. #include "cmProcObj.h"
  26. #include "cmDspCtx.h"
  27. #include "cmDspClass.h"
  28. #include "cmDspSys.h"
  29. #include "cmDspPgm.h"
  30. #include "cmDspPgmPPMain.h"
  31. #include "cmAudioFile.h"
  32. #include "cmProcObj.h"
  33. #include "cmProc.h"
  34. #include "cmProc3.h"
  35. #include "cmVectOpsTemplateMain.h"
  36. #include "cmVectOps.h"
  37. /*
  38. subnet [ aout ] = fx_chain( ain, hzV )
  39. {
  40. cmpThreshDb = -40.0;
  41. cmpRatio = 4;
  42. cmpAtkMs = 30.0;
  43. cmpRlsMs = 100.0;
  44. dstInGain = 1.0;
  45. dstDSrate = 44100.0;
  46. dstBits = 24;
  47. eqMode = "LP";
  48. eqHz = hzV[ _i ];
  49. dlyMaxMs = 10000.0;
  50. dlyFb = 0.8;
  51. loop = loopRecd( );
  52. ps = pitchShift( );
  53. cmp = compressor( cmpThreshDb, cmpRatio, cmpAtkMs, cmpRlsMs );
  54. dst = distortion( dstInGain, dstDSrate, dstBits );
  55. eq = eq( eqMode, eqHz );
  56. dly = delay( dlyMaxMs, dlyFb );
  57. ain -> in.loop.out -> in.ps.out -> in.ps.out
  58. loop.out -> ps.in;
  59. ps.out -> cmp.in;
  60. cmp.out -> dst.in;
  61. dst.out -> eq.in;
  62. eq.out -> dly.in;
  63. dly.out -> aout
  64. }
  65. audInMapV = [ 0, 1, 0, 1];
  66. audOutMapV = [ 0, 1 ];
  67. hzV = [ 110 220 440 880 ];
  68. ain = audioInput( audioInMap, 1.0 )[ chCnt ];
  69. ef = envFollower( )[ chCnt ];
  70. mtr = meter(0.0,1.0,0.0)[ chCnt ];
  71. fx = fx_chain( ain )( hzV )[ chCnt ];
  72. aout = audioOutput( audioOutMap, 1.0 )[ chCnt ];
  73. ain.out -> ef.in
  74. ef.rms -> mtr.in
  75. */
  76. // Use the resource int arrays 'pitchList' and 'groupList' to create
  77. // the following resource int arrays:
  78. // CDmidi - MIDI pitch of all chord notes
  79. // CD0midi - MIDI pitch of all low/high chord notes
  80. // CD1midi - MIDI pitch of all middle chord notes
  81. // NONmidi - MIDI pitch of all non-chord notes.
  82. // CDchan - channel index of all chord notes
  83. // CD0chan - channel index of all low/high chord notes
  84. // CD1chan - channel index of all middle chord notes
  85. // NONchan - channel index of all non-chord notes.
  86. //
  87. cmDspRC_t _cmDspPgm_Main_ProcRsrc( cmDspSysH_t h, cmErr_t* err )
  88. {
  89. cmDspRC_t rc;
  90. unsigned* midiList = NULL;
  91. unsigned midiCnt = 0;
  92. unsigned* groupList = NULL;
  93. unsigned groupCnt = 0;
  94. const cmChar_t* midiListRsrcLabel = "midiList";
  95. const cmChar_t* groupListRsrcLabel = "groupList";
  96. cmJsonH_t jsH = cmDspSysPgmRsrcHandle(h);
  97. unsigned i,j,k;
  98. if((rc = cmDspRsrcUIntArray(h,&midiCnt,&midiList,midiListRsrcLabel,NULL)) != kOkDspRC )
  99. {
  100. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",midiListRsrcLabel);
  101. goto errLabel;
  102. }
  103. if((rc = cmDspRsrcUIntArray(h,&groupCnt,&groupList,groupListRsrcLabel,NULL)) != kOkDspRC )
  104. {
  105. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",groupListRsrcLabel);
  106. goto errLabel;
  107. }
  108. if( midiCnt != groupCnt )
  109. {
  110. rc = cmErrMsg(err,kInvalidStateDspRC,"The resource arrays:%s and %s were not the same length.",midiListRsrcLabel,groupListRsrcLabel);
  111. goto errLabel;
  112. }
  113. for(i=0; i<4; ++i)
  114. {
  115. int midi[ midiCnt ];
  116. int chan[ midiCnt ];
  117. const cmChar_t* label = NULL;
  118. const cmChar_t* label1;
  119. for(j=0,k=0; j<midiCnt; ++j)
  120. {
  121. if( (i<=2 && groupList[j] == i) || (i==3 && groupList[j]!=0) )
  122. {
  123. midi[k] = midiList[j];
  124. chan[k] = j;
  125. ++k;
  126. }
  127. }
  128. switch( i )
  129. {
  130. case 0:
  131. label = "NON";
  132. break;
  133. case 1:
  134. label = "CD0";
  135. break;
  136. case 2:
  137. label = "CD1";
  138. break;
  139. case 3:
  140. label = "CD";
  141. break;
  142. }
  143. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("%smidi",label), k, midi ) != kOkJsRC )
  144. {
  145. rc = cmErrMsg(err,kJsonFailDspRC,"The chord detector pitch resource '%s' could not be created.", cmStringNullGuard(label1));
  146. goto errLabel;
  147. }
  148. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("%schan",label), k, chan) != kOkJsRC )
  149. {
  150. rc = cmErrMsg(err,kJsonFailDspRC,"The chord detector channel index resource '%s' could not be created.", cmStringNullGuard(label1));
  151. goto errLabel;
  152. }
  153. }
  154. errLabel:
  155. return rc;
  156. }
  157. // Use the resource int arrays 'MidiList',"MachineList", "ChordList" and 'GroupList' to create
  158. // the resource int arrays. XXXchan arrays contain indexes between 0 and 15. When used with
  159. // the chord detector this the 'local' channels are 0-15 and the remote channels are 16-31.
  160. // NLCDmidi - MIDI pitch of all local chord notes
  161. // NLCD0midi - MIDI pitch of all local low single notes
  162. // NLCD1midi - MIDI pitch of all local middle single notes
  163. // NLEEmidi - MIDI pitch of all local e-e single notes.
  164. // NLCDchan - channel index of all local chord notes
  165. // NLCD0chan - channel index of all local high single notes
  166. // NLCD1chan - channel index of all local middle single notes
  167. // NLEEchan - channel index of all local e-e single notes.
  168. // NRCDmidi - MIDI pitch of all remote chord notes
  169. // NRCD0midi - MIDI pitch of all remote low single notes
  170. // NRCD1midi - MIDI pitch of all remote middle single notes
  171. // NREEmidi - MIDI pitch of all remote e-e single notes.
  172. // NRCDchan - channel index of all remote chord notes
  173. // NRCD0chan - channel index of all remote high single notes
  174. // NRCD1chan - channel index of all remote middle single notes
  175. // NREEchan - channel index of all remote e-e single notes.
  176. // 'local' refers to the machine running the chord detector
  177. // 'remote' refers to the machine not running the chord detector
  178. cmDspRC_t _cmDspPgm_Main_NetProcRsrc( cmDspSysH_t h, cmErr_t* err )
  179. {
  180. cmDspRC_t rc = kOkDspRC;
  181. const cmChar_t* midiListRsrcLabel = "MidiList";
  182. unsigned* midiList = NULL;
  183. unsigned midiCnt = 0;
  184. const cmChar_t* machListRsrcLabel = "MachineList";
  185. unsigned* machList = NULL;
  186. unsigned machCnt = 0;
  187. const cmChar_t* groupListRsrcLabel = "GroupList";
  188. unsigned* groupList = NULL;
  189. unsigned groupCnt = 0;
  190. const cmChar_t* chordListRsrcLabel = "ChordList";
  191. unsigned* chordList = NULL;
  192. unsigned chordCnt = 0;
  193. cmJsonH_t jsH = cmDspSysPgmRsrcHandle(h);
  194. const cmChar_t* localNetNodeLabel = NULL;
  195. unsigned localNetNodeId = cmInvalidId;
  196. bool verboseFl = false;
  197. unsigned i,j,k,m;
  198. // get the network node id of this machine
  199. if(( cmDspRsrcString(h, &localNetNodeLabel, "cdLocalNetNode", NULL )) != kOkDspRC )
  200. {
  201. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource 'cdLocalNetNode' could not be read.");
  202. goto errLabel;
  203. }
  204. if(( localNetNodeId = cmDspSysNetNodeLabelToId(h,localNetNodeLabel)) == cmInvalidId )
  205. {
  206. cmErrMsg(err,kInvalidArgDspRC,"The network node label '%s' is not valid.",cmStringNullGuard(localNetNodeLabel));
  207. goto errLabel;
  208. }
  209. // get the pitch assigned to each channel
  210. if((rc = cmDspRsrcUIntArray(h,&midiCnt,&midiList,midiListRsrcLabel,NULL)) != kOkDspRC )
  211. {
  212. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",midiListRsrcLabel);
  213. goto errLabel;
  214. }
  215. // get the network node id of each channel
  216. if((rc = cmDspRsrcUIntArray(h,&machCnt,&machList,machListRsrcLabel,NULL)) != kOkDspRC )
  217. {
  218. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",machListRsrcLabel);
  219. goto errLabel;
  220. }
  221. // get the group id of each channel
  222. if((rc = cmDspRsrcUIntArray(h,&groupCnt,&groupList,groupListRsrcLabel,NULL)) != kOkDspRC )
  223. {
  224. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",groupListRsrcLabel);
  225. goto errLabel;
  226. }
  227. // get the chord detector flag for each channel
  228. if((rc = cmDspRsrcUIntArray(h,&chordCnt,&chordList,chordListRsrcLabel,NULL)) != kOkDspRC )
  229. {
  230. rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",chordListRsrcLabel);
  231. goto errLabel;
  232. }
  233. if( midiCnt != groupCnt || midiCnt != machCnt)
  234. {
  235. rc = cmErrMsg(err,kInvalidStateDspRC,"The resource arrays:%s, %s and %s were not all the same length.",midiListRsrcLabel,machListRsrcLabel,groupListRsrcLabel);
  236. goto errLabel;
  237. }
  238. if( 1 )
  239. {
  240. const cmChar_t* label1;
  241. unsigned ten = 10;
  242. int nsChSelChV[ midiCnt ]; // note selector chord port [0, 5]
  243. int nsChSelChIdxV[ midiCnt ]; // index on note selector port
  244. int nsNcSelChV[ midiCnt ]; // note selector single-note port [ 2, 3, 4, 7,8,9 ]
  245. int nsNcSelChIdxV[ midiCnt ]; // index on note selector single-note port
  246. unsigned chIdxCntV[ ten ]; // next index for each note selector port
  247. cmVOU_Fill(chIdxCntV,ten,0);
  248. for(i=0; i<midiCnt; ++i)
  249. {
  250. unsigned localFl = i<16;
  251. unsigned selIdx = localFl ? 0 : 5; // chord port
  252. unsigned chordChFl = chordList[i] != 0; // is this a chord channel
  253. nsChSelChV[i] = cmInvalidIdx;
  254. nsChSelChIdxV[i] = cmInvalidIdx;
  255. if( chordChFl )
  256. {
  257. nsChSelChV[ i ] = selIdx;
  258. nsChSelChIdxV[ i ] = chIdxCntV[ selIdx ];
  259. chIdxCntV[ selIdx ] += 1;
  260. }
  261. switch( groupList[i] )
  262. {
  263. case 0: selIdx = localFl ? 4 : 9; break; // e-e group
  264. case 1: selIdx = localFl ? 2 : 7; break; // hi/lo group
  265. case 2: selIdx = localFl ? 3 : 8; break; // mid group
  266. default:
  267. { assert(0); }
  268. }
  269. assert( selIdx < ten );
  270. nsNcSelChV[ i ] = selIdx;
  271. nsNcSelChIdxV[ i ] = chIdxCntV[ selIdx ];
  272. chIdxCntV[ selIdx ] += 1;
  273. }
  274. if( verboseFl )
  275. {
  276. cmVOI_PrintL("nsChSelChV", err->rpt, 1, midiCnt, nsChSelChV );
  277. cmVOI_PrintL("nsChSelChIdxV", err->rpt, 1, midiCnt, nsChSelChIdxV );
  278. cmVOI_PrintL("nsNcSelChV", err->rpt, 1, midiCnt, nsNcSelChV );
  279. cmVOI_PrintL("nsNcSelChIdxV", err->rpt, 1, midiCnt, nsNcSelChIdxV );
  280. }
  281. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsChSelChV", midiCnt, nsChSelChV ) != kOkJsRC )
  282. {
  283. rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1));
  284. goto errLabel;
  285. }
  286. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsChSelChIdxV", midiCnt, nsChSelChIdxV ) != kOkJsRC )
  287. {
  288. rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1));
  289. goto errLabel;
  290. }
  291. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsNcSelChV", midiCnt, nsNcSelChV ) != kOkJsRC )
  292. {
  293. rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1));
  294. goto errLabel;
  295. }
  296. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsNcSelChIdxV", midiCnt, nsNcSelChIdxV ) != kOkJsRC )
  297. {
  298. rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1));
  299. goto errLabel;
  300. }
  301. for(i=0; i<ten; ++i)
  302. {
  303. int midi[ midiCnt ];
  304. int chan[ midiCnt ];
  305. for(j=0,k=0; j<midiCnt; ++j)
  306. {
  307. m = i;
  308. if( m == 1 || m == 6 )
  309. m -= 1;
  310. if( nsChSelChV[j] == m )
  311. {
  312. midi[k] = midiList[j];
  313. chan[k] = j>15 ? j-16 : j;
  314. assert( k == nsChSelChIdxV[j] );
  315. ++k;
  316. }
  317. if( nsNcSelChV[j] == m )
  318. {
  319. midi[k] = midiList[j];
  320. chan[k] = j>15 ? j-16 : j;
  321. assert( k == nsNcSelChIdxV[j] );
  322. ++k;
  323. }
  324. }
  325. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("nsMidi-%i",i), k, midi ) != kOkJsRC )
  326. {
  327. rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1));
  328. goto errLabel;
  329. }
  330. if( verboseFl )
  331. cmVOI_PrintL(label1, err->rpt, 1, k, midi );
  332. if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("nsChan-%i",i), k, chan ) != kOkJsRC )
  333. {
  334. rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1));
  335. goto errLabel;
  336. }
  337. if( verboseFl )
  338. cmVOI_PrintL(label1, err->rpt, 1, k, chan );
  339. }
  340. }
  341. errLabel:
  342. return rc;
  343. }
  344. const cmChar_t* _cmDspPP_SelCheckTitle( cmDspSysH_t h, unsigned i )
  345. { return _cmDspPP_CircuitDesc(i)->title; }
  346. cmDspRC_t _cmDspSysPgm_Main( cmDspSysH_t h, void** userPtrPtr )
  347. {
  348. cmDspRC_t rc = kOkDspRC;
  349. const cmChar_t* chCfgFn = NULL;
  350. cmCtx_t* cmCtx = cmDspSysPgmCtx(h);
  351. double efOnThrDb = -40;
  352. double efOffThrDb = -70;
  353. double efMaxDb = -15;
  354. unsigned circuitCnt = _cmDspPP_CircuitDescCount();
  355. unsigned resetSymId = cmDspSysRegisterStaticSymbol(h,"_reset");
  356. bool inFileFl = false;
  357. cmErr_t err;
  358. _cmDspPP_Ctx_t ctx;
  359. cmDspPP_CircuitSwitch_t sw;
  360. memset(&sw,0,sizeof(sw));
  361. // set up the global context record
  362. memset(&ctx,0,sizeof(ctx));
  363. ctx.oChCnt = 2;
  364. ctx.err = &err;
  365. cmErrSetup(&err,&cmCtx->rpt,"PP Main");
  366. // create the individual non-networked chord detector resource arrays from the base resource arrays
  367. if((rc =_cmDspPgm_Main_ProcRsrc(h,&err)) != kOkDspRC )
  368. goto errLabel;
  369. // create the individual networked chord detector resource arrays from the base resource arrays
  370. if((rc = _cmDspPgm_Main_NetProcRsrc(h,&err)) != kOkDspRC )
  371. goto errLabel;
  372. // get the channel cfg configuration file name
  373. if( cmJsonPathToString( cmDspSysPgmRsrcHandle(h), NULL, NULL, "chCfgFn", &chCfgFn ) != kOkJsRC )
  374. {
  375. rc = cmErrMsg(&err,kRsrcNotFoundDspRC,"The 'chCfgFn' resource was not found.");
  376. goto errLabel;
  377. }
  378. // get the count of channels from the ch. cfg. array
  379. if(( ctx.iChCnt = cmChCfgChannelCount(cmCtx,chCfgFn,&ctx.nsCnt)) == 0 )
  380. {
  381. rc = cmErrMsg(&err,kPgmCfgFailDspRC,"Unable to obtain the channel count from '%s'.",cmStringNullGuard(chCfgFn));
  382. goto errLabel;
  383. }
  384. if( rc == kOkDspRC )
  385. {
  386. unsigned inChCnt,outChCnt;
  387. // channel cfg
  388. ctx.chCfg = cmDspSysAllocInst( h, "ChCfg", NULL, 1, chCfgFn );
  389. // global printer
  390. ctx.print = cmDspSysAllocInst( h, "Printer", NULL, 1, ">" );
  391. cmDspInst_t** ain;
  392. cmDspInst_t* phs;
  393. // audio input
  394. if( inFileFl )
  395. {
  396. unsigned wtSmpCnt = (unsigned)cmDspSysSampleRate(h);
  397. unsigned wtMode = 1; //file mode
  398. const cmChar_t* fn = "/home/kevin/media/audio/gate_detect/gate_detect2.aif";
  399. phs = cmDspSysAllocInst(h,"Phasor", NULL, 0 );
  400. ain = cmDspSysAllocInstArray(h, ctx.iChCnt, "WaveTable", NULL, NULL, 3, wtSmpCnt, wtMode, fn );
  401. inChCnt = ctx.iChCnt;
  402. }
  403. else
  404. {
  405. ain = cmDspSysAllocAudioInAR( h, "audioInMap", 1.0, &inChCnt );
  406. }
  407. // envelope followers and RMS meters
  408. cmDspSysAllocLabel(h,"EF Gates",kLeftAlignDuiId );
  409. cmDspInst_t** ef = cmDspSysAllocInstArray( h, ctx.iChCnt,"EnvFollow", NULL, NULL, 0 );
  410. cmDspInst_t** mtr = cmDspSysAllocInstArray( h, ctx.iChCnt,"Meter", "mtr", NULL, 3, 0.0, 0.0, 1.0 );
  411. // Level meters
  412. cmDspSysNewColumn(h,200);
  413. cmDspSysAllocLabel(h,"Level",kLeftAlignDuiId );
  414. cmDspInst_t** lvl = cmDspSysAllocInstArray( h, ctx.iChCnt,"Meter", "lvl", NULL, 3, 0.0, 0.0, 1.0 );
  415. assert( inChCnt == ctx.iChCnt );
  416. // Onset count displays
  417. cmDspSysNewColumn(h,200);
  418. cmDspInst_t** onn = cmDspSysAllocInstArray( h, ctx.iChCnt,"Scalar", "on", NULL, 5, kNumberDuiId, 0.0, 10000.0, 1.0, 0.0 );
  419. cmDspSysNewColumn(h,200);
  420. // program reset button
  421. cmDspInst_t* resetBtn = cmDspSysAllocButton( h, "reset", 0 );
  422. cmDspSysAssignInstAttrSymbol(h,resetBtn, resetSymId );
  423. // circuit selection check-boxes
  424. cmDspInst_t** csel = cmDspSysAllocInstArray( h, circuitCnt, "Button", NULL, _cmDspPP_SelCheckTitle, 2, kCheckDuiId, 0.0 );
  425. cmDspSysNewColumn(h,200);
  426. cmDspSysAllocLabel(h,"Out Gains",kLeftAlignDuiId );
  427. // output gain controls
  428. cmDspInst_t** ogain = cmDspSysAllocInstArray( h, ctx.oChCnt,"Scalar", "mgain", NULL, 5, kNumberDuiId, 0.0, 10.0, 0.01, 1.0);
  429. // envelope follower parameters
  430. cmDspInst_t* onThr = cmDspSysAllocScalar( h, "On Thresh",-100.0, 0.0, 0.1, efOnThrDb);
  431. cmDspInst_t* offThr = cmDspSysAllocScalar( h, "Off Thresh",-100.0, 0.0, 0.1, efOffThrDb);
  432. cmDspInst_t* maxDb = cmDspSysAllocScalar( h, "Max Db", -100.0, 0.0, 0.1, efMaxDb);
  433. // switcher and circuits
  434. _cmDspPP_CircuitSwitchAlloc(h, &ctx, &sw, resetBtn, csel, ain, ef);
  435. // audio output
  436. cmDspInst_t** aout = cmDspSysAllocAudioOutAR( h, "audioOutMap", 1.0, &outChCnt );
  437. assert( outChCnt == ctx.oChCnt );
  438. //cmDspInst_t* prt = cmDspSysAllocInst( h, "Printer", NULL, 2, "", 250 );
  439. // check for errors
  440. if((rc = cmDspSysLastRC(h)) != kOkDspRC )
  441. goto doneLabel;
  442. if( inFileFl )
  443. {
  444. cmDspSysConnectAudio11N1( h, phs, "out", ain, "phs", ctx.iChCnt ); // phs -> wt
  445. cmDspSysConnectAudioN1N1( h, ain, "out", ef, "in", ctx.iChCnt ); // wt -> EF
  446. }
  447. else
  448. {
  449. cmDspSysConnectAudioN1N1( h, ain, "out", ef, "in", ctx.iChCnt ); // ain -> EF
  450. }
  451. cmDspSysInstallCb1NN1( h, ctx.chCfg, "gain", ain, "gain", ctx.iChCnt ); // chCfg -> ain (gain)
  452. cmDspSysConnectAudioN1N1( h, sw.omix, "out", aout, "in", ctx.oChCnt ); // Sw.mix -> aout
  453. cmDspSysInstallCbN1N1( h, ogain, "val", aout, "gain", ctx.oChCnt ); // gain -> aout
  454. cmDspSysInstallCb( h, resetBtn,"sym", ctx.chCfg, "sel", NULL ); // reset -> chCfg
  455. cmDspSysInstallCbN1N1( h, ef, "gate", mtr, "in", ctx.iChCnt ); // EF -> meter (gate)
  456. cmDspSysInstallCbN1N1( h, ef, "level", lvl, "in", ctx.iChCnt ); // EF -> meter (level)
  457. cmDspSysInstallCbN1N1( h, ef, "ons", onn, "val", ctx.iChCnt );
  458. cmDspSysInstallCb11N1( h, onThr, "val", ef, "ondb", ctx.iChCnt ); // EF sensivity settings
  459. cmDspSysInstallCb11N1( h, offThr, "val", ef, "offdb", ctx.iChCnt ); //
  460. cmDspSysInstallCb11N1( h, maxDb, "val", ef, "maxdb", ctx.iChCnt ); //
  461. //cmDspSysInstallCbN111( h, ef, "level", prt, "in", ctx.iChCnt );
  462. doneLabel:
  463. _cmDspPP_CircuitSwitchFree(h, &sw );
  464. }
  465. errLabel:
  466. if( rc != kOkDspRC )
  467. cmErrMsg(&err,rc,"'main' construction failed.");
  468. return rc;
  469. }