Programmable real-time audio signal processing application
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.

kcApp.cpp 53KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223
  1. #include <FL/Fl.H>
  2. #include <FL/Fl_Double_Window.H>
  3. #include <FL/Fl_Menu_Item.H>
  4. #include <Fl/Fl_Menu_Bar.H>
  5. #include <Fl/Fl_Button.H>
  6. #include <Fl/Fl_Check_Button.H>
  7. #include <Fl/Fl_Text_Buffer.H>
  8. #include <Fl/Fl_Text_Display.H>
  9. #include <Fl/Fl_Box.H>
  10. #include <Fl/Fl_Tabs.H>
  11. #include <Fl/Fl_File_Chooser.H>
  12. #include <Fl/Fl_Value_Slider.H>
  13. #include <Fl/Fl_Menu_Button.H>
  14. #include <Fl/Fl_Select_Browser.H>
  15. #include <Fl/Fl_Value_Input.H>
  16. #include <Fl/Fl_Progress.H>
  17. #include "Fl_Vert_Progress.h"
  18. #include "Fl_File_Btn.h"
  19. #include "Fl_Splitter.h"
  20. #include "cmGlobal.h"
  21. #include "cmFloatTypes.h"
  22. #include "cmRpt.h"
  23. #include "cmErr.h"
  24. #include "cmCtx.h"
  25. #include "cmMem.h"
  26. #include "cmMallocDebug.h"
  27. #include "cmLinkedHeap.h"
  28. #include "cmText.h"
  29. #include "cmSymTbl.h"
  30. #include "cmJson.h"
  31. #include "cmFileSys.h"
  32. #include "cmPrefs.h"
  33. #include "cmAudioFile.h"
  34. #include "cmThread.h"
  35. #include "cmSymTbl.h"
  36. #include "cmProcTest.h"
  37. #include "cmDspValue.h"
  38. #include "cmMsgProtocol.h"
  39. #include "cmAudDspIF.h"
  40. #include "cmAudDspLocal.h"
  41. #include "cmAudioFile.h"
  42. #include "cmAudioFileMgr.h"
  43. #include "cmMidi.h"
  44. #include "cmMidiFile.h"
  45. #include "cmTimeLine.h"
  46. #include "cmScore.h"
  47. #include "cmdIf.h"
  48. #include "tlCtl.h"
  49. #include "kcApp.h"
  50. #include "cmGr.h"
  51. #include "cmGrDevCtx.h"
  52. #include "cmGrPlot.h"
  53. #include "cmGrPage.h"
  54. #include "cmGrFltk.h"
  55. #define TIMER_PERIOD (1.0/20.0) // 50ms
  56. kcApp::kcApp(cmCtx_t* ctx, cmPrH_t prH, cmTsMp1cH_t printqH, int w, int h, const cmChar_t* title, cmAiH_t aiH, int argc, char* argv[] )
  57. : Fl_Double_Window(w, h,title),
  58. _ctx(ctx),_prH(prH),_aiH(aiH),
  59. _menu(NULL),_con(NULL),_tabs(NULL),_mstr_grp(NULL),
  60. _as_btn(NULL),_ai_btn(NULL),_ao_btn(NULL),_pgm_btn(NULL),
  61. _ss_btn(NULL),_sr_btn(NULL),_ena_chk(NULL),
  62. _pageList(NULL),_ctlList(NULL),
  63. _stopTimerFl(false),_newPageFl(true),
  64. _incrColW(0),_colW(0),_horzBordFl(false),_horzBord(0),
  65. _ssCnt(0),_ssArray(0),_ssPhase(0),_ssUpdateFl(false),
  66. _printqH(printqH),_printFl(0),
  67. _tlCtl(NULL)
  68. {
  69. // install a callback to cleanup when the app window closes
  70. // (the btn callbacks and _getApp() rely on a pointer to 'this' being found in kcApp.user_data())
  71. callback(_s_callback,this);
  72. // the main window is divided between the menu bar on top
  73. // and a horizontal splitter on the bottom
  74. begin();
  75. _createMenu(w,kMenuH);
  76. end();
  77. // Create a tab view
  78. add(_tabs = new Fl_Tabs(this->x(),this->y()+kMenuH,this->w(),this->h()-kMenuH));
  79. _tabs->callback(_s_tab_cb,this);
  80. _tabs->end();
  81. int tx=x(),ty=y(),th=this->h(),tw=this->w();
  82. _tabs->client_area(tx,ty,tw,th);
  83. // Create the 'Setup' tab group
  84. Fl_Group* setup_grp = new Fl_Group(tx,ty,tw,th,"Setup");
  85. _tabs->add(setup_grp);
  86. _createSetupDlg(setup_grp);
  87. // Create the console window
  88. Fl_Group* con_grp = new Fl_Group(tx,ty,tw,th,"Console");
  89. _tabs->add(con_grp);
  90. Fl_Text_Buffer* buf = new Fl_Text_Buffer();
  91. _con = new Fl_Text_Display(tx,ty,tw,th);
  92. _con->buffer(buf);
  93. con_grp->add(_con);
  94. // Create the master group
  95. _tabs->add(_mstr_grp = new Fl_Group(tx,ty,tw,th,"Master"));
  96. // Create an empty tab group and make it resizable
  97. // to prevent the other tab groups from being resizable.
  98. Fl_Group* wdgt = new Fl_Group(tx,ty+30,1,1);
  99. _tabs->add(wdgt);
  100. _tabs->resizable(wdgt); // make other tabs non-resizable
  101. // make the splitter the resizable group element (thereby making the menu non-resizable).
  102. // see:http://fltk.org/articles.php?L415+I0+T+M1000+P1
  103. resizable(_tabs);
  104. show(argc, argv);
  105. // direct all output to the console window
  106. cmRptSetup(&_ctx->rpt,_s_print,_s_print, this);
  107. cmTsMp1cSetCbFunc(_printqH, _s_print_queue_cb, this );
  108. // install a timer to check for messages from the engine
  109. Fl::add_timeout(TIMER_PERIOD,_s_status_timeout_cb,this);
  110. }
  111. kcApp::~kcApp()
  112. {
  113. _clearCtlList(true);
  114. _clearSsArray();
  115. }
  116. void kcApp::resize(int x, int y, int w, int h)
  117. {
  118. Fl_Double_Window::resize(x, y, w, h);
  119. cmPrefsPathSetInt(_prH,"appWndW",w);
  120. cmPrefsPathSetInt(_prH,"appWndH",h);
  121. cmPrefsPathSetInt(_prH,"appWndX",x);
  122. cmPrefsPathSetInt(_prH,"appWndY",y);
  123. }
  124. void kcApp::tlCtlNewTimeLineFile( tlCtl* tlCtl, const cmChar_t* fn )
  125. {}
  126. void kcApp::tlCtlNewScoreFile( tlCtl* tlCtl, const cmChar_t* fn )
  127. {}
  128. void kcApp::_createSetupDlg( Fl_Group* grp )
  129. {
  130. int ctl_width = 200;
  131. int vBord = 5;
  132. int xx = grp->x() + 5;
  133. int yy = grp->y() + vBord;
  134. grp->begin();
  135. Fl_Button* btn = new Fl_Button(xx,yy,200,kMenuH,"Audio Device Report");
  136. btn->callback( _s_btn_cb, kAudDevRptBtnId );
  137. yy += btn->h() + vBord;
  138. _as_btn = new Fl_Menu_Button(xx,yy,ctl_width,kMenuH,"Audio System Cfg");
  139. _as_btn->callback( _s_btn_cb, kAudioSysCfgBtnId);
  140. yy += _as_btn->h() + vBord;
  141. _ai_btn = new Fl_Menu_Button(xx,yy,ctl_width,kMenuH,"Audio Input Devices");
  142. _ai_btn->callback( _s_btn_cb, kInAudDevBtnId);
  143. yy += _ai_btn->h() + vBord;
  144. _ao_btn = new Fl_Menu_Button(xx,yy,ctl_width,kMenuH,"Audio Output Devices");
  145. _ao_btn->callback( _s_btn_cb, kOutAudDevBtnId);
  146. yy += _ao_btn->h() + vBord;
  147. _pgm_btn = new Fl_Menu_Button(xx,yy,ctl_width,kMenuH,"Programs");
  148. _pgm_btn->callback( _s_btn_cb, kPgmBtnId);
  149. yy += _pgm_btn->h() + vBord;
  150. _ss_btn = new Fl_Menu_Button(xx,yy,ctl_width,kMenuH,"Sub-System");
  151. _ss_btn->callback( _s_btn_cb, kSubSystemIdxBtnId);
  152. yy += _ss_btn->h() + vBord;
  153. _sr_btn = new Fl_Menu_Button(xx,yy,ctl_width,kMenuH,"Sample Rate");
  154. _sr_btn->callback( _s_btn_cb, kSrateBtnId);
  155. _sr_btn->add("44100",0,NULL,(void*)44100,0);
  156. _sr_btn->add("48000",0,NULL,(void*)48000,0);
  157. _sr_btn->add("96000",0,NULL,(void*)96000,0);
  158. yy += _sr_btn->h() + vBord;
  159. btn = new Fl_Button(xx,yy,ctl_width,kMenuH,"Test");
  160. btn->callback( _s_btn_cb, kTestBtnId );
  161. yy += btn->h() + vBord;
  162. btn = new Fl_Button(xx,yy,200,kMenuH,"Print program");
  163. btn->callback( _s_btn_cb, kPrintPgmBtnId );
  164. yy += btn->h() + vBord;
  165. _ena_chk = new Fl_Check_Button(xx,yy,ctl_width,kMenuH,"Enable Audio");
  166. _ena_chk->callback( _s_btn_cb, kEnableBtnId );
  167. yy += _ena_chk->h() + vBord;
  168. // place this ctrl in the lower left corner to prevent the other controls from resizing
  169. Fl_Box* bx = new Fl_Box(FL_NO_BOX,xx+ctl_width,yy,10,10,NULL);
  170. grp->resizable(bx);
  171. grp->end();
  172. }
  173. void kcApp::_createMenu(int w, int h)
  174. {
  175. Fl_Menu_Item items[] =
  176. {
  177. { "kc", 0, 0, 0, FL_SUBMENU },
  178. { "&About", FL_COMMAND + 'a', (Fl_Callback*)_s_menu_cb, (void*)kAboutMenuId },
  179. { "&Quit", FL_COMMAND + 'q', (Fl_Callback*)_s_menu_cb, (void*)kQuitMenuId },
  180. { 0 },
  181. { 0 }
  182. };
  183. _menu = new Fl_Menu_Bar(0,0,w,h);
  184. _menu->copy(items);
  185. this->add(_menu);
  186. }
  187. kcApp::page_t* kcApp::_createPage( const char* title )
  188. {
  189. int tx,ty,th,tw;
  190. _tabs->client_area(tx,ty,tw,th);
  191. page_t* page = new page_t;
  192. page->link = _pageList;
  193. _pageList = page;
  194. _newPageFl = true;
  195. // Create the 'Controls' tab group
  196. _tabs->begin();
  197. page->grp = new Fl_Group(tx,ty,tw,th,title);
  198. page->grp->begin();
  199. Fl_Box* bx = new Fl_Box(FL_NO_BOX,page->grp->x()+page->grp->w(),page->grp->y()+page->grp->h(),1,1,NULL);
  200. page->grp->resizable(bx);
  201. page->grp->end();
  202. _tabs->end();
  203. return page;
  204. }
  205. // return the count of engine ctls
  206. unsigned kcApp::_getCtlCount() const
  207. {
  208. unsigned cnt = 0;
  209. ctl_t* cp = _ctlList;
  210. for(; cp!=NULL; cp=cp->linkPtr)
  211. ++cnt;
  212. return cnt;
  213. }
  214. // delete all engine ctls - (except maybe the master ctrl's)
  215. void kcApp::_clearCtlList(bool mstrFl)
  216. {
  217. ctl_t* ncl = NULL;
  218. ctl_t* cp = _ctlList;
  219. while( cp != NULL )
  220. {
  221. ctl_t* np = cp->linkPtr;
  222. // delete the ctrl unless it is a master ctl and the mstrFl is set
  223. if( cp->mstrFl==false || mstrFl )
  224. {
  225. delete cp;
  226. }
  227. else
  228. {
  229. // append the master ctl to the new ctl list
  230. cp->linkPtr = ncl;
  231. ncl = cp;
  232. }
  233. cp = np;
  234. }
  235. // clear the page groups and pages
  236. page_t* pg = _pageList;
  237. while( pg != NULL )
  238. {
  239. page_t* np = pg->link;
  240. pg->grp->clear();
  241. delete pg->grp;
  242. delete pg;
  243. pg = np;
  244. }
  245. _pageList = NULL;
  246. //ctl_grp->clear();
  247. _ctlList = ncl; // make the new ctl list the current ctl list
  248. if( mstrFl )
  249. _mstr_grp->clear();
  250. _tlCtl = NULL;
  251. }
  252. void kcApp::_clearSsArray()
  253. {
  254. if( _ssArray != NULL )
  255. {
  256. delete[] _ssArray;
  257. _ssArray = NULL;
  258. }
  259. _ssCnt = 0;
  260. }
  261. // find a engine ui ctl given a dsp instance id
  262. kcApp::ctl_t* kcApp::_findCtl( unsigned instId, unsigned asSubIdx, unsigned mstrFl )
  263. {
  264. ctl_t* cp = _ctlList;
  265. for(; cp!=NULL; cp=cp->linkPtr)
  266. if( cp->instId == instId && cp->asSubIdx==asSubIdx && cp->mstrFl==mstrFl )
  267. return cp;
  268. //printf("not found:0x%x ssi:%i mstr:%i\n",instId,asSubIdx,mstrFl);
  269. return NULL;
  270. }
  271. // calc. the position and size of a new ctl being created
  272. // at the request of the engine
  273. void kcApp::_getNewCtlPosn( const cmDspUiHdr_t* m, int& x, int& y, int& w, int& h )
  274. {
  275. enum { kPageH=700, kCtlH=30, kCtlW=200, kHBord=2, kVBord=2 };
  276. // if this is control is being placed in the 'master' group
  277. if( m->uiId == cmInvalidId )
  278. {
  279. //unsigned devIdx = cmAudioSysUiInstIdToDevIndex(m->instId);
  280. unsigned chIdx = cmAudioSysUiInstIdToChIndex(m->instId);
  281. unsigned outFl = !cmAudioSysUiInstIdToInFlag(m->instId);
  282. unsigned ctlId = cmAudioSysUiInstIdToCtlId(m->instId);
  283. int xOffs = 20;
  284. int yOffs = 100;
  285. int chH = 205;
  286. int chW = 44;
  287. int sldrH = 120;
  288. int sldrW = 20;
  289. int chkH = 20;
  290. int chkW = 35;
  291. x = xOffs + (chIdx * chW);
  292. y = yOffs + (m->asSubIdx * 2 * chH) + (outFl * chH);
  293. switch( ctlId )
  294. {
  295. // slider
  296. case kSliderUiAsId: w=sldrW; h=sldrH; break;
  297. // meter
  298. case kMeterUiAsId: w=sldrW; h=sldrH; x+=sldrW; break;
  299. // mute
  300. case kMuteUiAsId: w=chkW; h=chkH; y+=sldrH + 2; break;
  301. // tone
  302. case kToneUiAsId: w=chkW; h=chkH; y+=sldrH + chkH + 4; break;
  303. // pass
  304. case kPassUiAsId: w=chkW; h=chkH; y+=sldrH + 2*chkH + 6; break;
  305. default:
  306. { assert(0); }
  307. }
  308. return;
  309. }
  310. // if this control is being placed in the 'controls' group
  311. ctl_t* cp = _ctlList;
  312. if( w == 0 )
  313. {
  314. if( _colW == 0 )
  315. _colW = kCtlW;
  316. w = _colW;
  317. }
  318. if( h == 0 )
  319. h = kCtlH;
  320. // skip over controls that are assigned to the 'master' group
  321. while(cp != NULL && cp->mstrFl )
  322. cp = cp->linkPtr;
  323. // if the page list is empty - create a default blank page
  324. if( _pageList == NULL )
  325. _createPage("Controls");
  326. Fl_Group* ctl_grp = _pageList->grp;
  327. // if the ctl list is empty
  328. if( cp == NULL || _newPageFl )
  329. {
  330. _newPageFl = false;
  331. x = kHBord + ctl_grp->x();
  332. y = kVBord + ctl_grp->y();
  333. _horzBord = y;
  334. }
  335. else
  336. {
  337. // if a new horizontal - upper border was requested
  338. if( _horzBordFl )
  339. {
  340. _horzBordFl = false;
  341. // locate the current control with the max bottom coordinate
  342. ctl_t* tp = cp;
  343. if( tp != NULL )
  344. {
  345. int maxY = tp->wdgtPtr->y() + tp->wdgtPtr->h();
  346. while(tp!=NULL)
  347. {
  348. if( tp->mstrFl == false && (tp->wdgtPtr->y() + tp->wdgtPtr->h()) > maxY )
  349. maxY = tp->wdgtPtr->y() + tp->wdgtPtr->h();
  350. tp = tp->linkPtr;
  351. }
  352. // set the new upper boundary to just below the bottom of
  353. // the lowest control
  354. _horzBord = maxY + kVBord*2;
  355. }
  356. x = kHBord + ctl_grp->x();
  357. y = _horzBord;
  358. }
  359. else
  360. {
  361. // use the last ctl inserted in the list
  362. // (the first ctl in the list)
  363. // to position the next ctl
  364. x = cp->wdgtPtr->x();
  365. y = cp->wdgtPtr->y() + cp->wdgtPtr->h() + kVBord;
  366. // if this control goes off the page or a new col was requested
  367. if( y+h > kPageH || _incrColW )
  368. {
  369. x += _colW + kHBord;
  370. _colW = _incrColW;
  371. _incrColW = 0;
  372. y = _horzBord;
  373. }
  374. }
  375. }
  376. }
  377. kcApp::ctl_t* kcApp::_createCtl( const cmDspUiHdr_t* m, unsigned typeId, int& x, int& y, int& w, int& h, bool posnFl )
  378. {
  379. ctl_t* cp = new ctl_t;
  380. cp->thisPtr = this;
  381. cp->asSubIdx = m->asSubIdx;
  382. cp->instId = m->instId;
  383. cp->typeId = typeId;
  384. cp->mstrFl = m->uiId == cmInvalidId;
  385. if( posnFl )
  386. _getNewCtlPosn(m,x,y,w,h);
  387. return cp;
  388. }
  389. void kcApp::_insertNewCtl( ctl_t* cp, const cmDspUiHdr_t* m, Fl_Widget* wdgt, unsigned* varIdArray, unsigned varIdCnt )
  390. {
  391. unsigned i;
  392. // _genNewCtlPosn() should have been called before this - where a new page list would have been created.
  393. assert( cp->mstrFl || (cp->mstrFl==false && _pageList != NULL) );
  394. Fl_Group* grp = cp->mstrFl ? _mstr_grp : _pageList->grp;
  395. cp->wdgtPtr = wdgt;
  396. cp->wdgtPtr->callback(_s_ctl_cb, cp );
  397. grp->add(cp->wdgtPtr);
  398. const unsigned* srcVarIdArray = cmDsvUIntCMtx(&m->value);
  399. assert( varIdArray != NULL && cmDsvEleCount(&m->value)==varIdCnt);
  400. for(i=0; i<varIdCnt; ++i)
  401. varIdArray[i] = srcVarIdArray[i];
  402. cp->linkPtr = _ctlList;
  403. _ctlList = cp;
  404. }
  405. // create a slider ctl at the request of the engine
  406. void kcApp::_createSlider( const cmDspUiHdr_t* m )
  407. {
  408. int x,y,w=0,h=0;
  409. ctl_t* cp = _createCtl(m, m->selId==kSliderDuiId? kSldrTypeId : kNumbTypeId, x,y,w,h );
  410. switch(m->selId)
  411. {
  412. case kSliderDuiId:
  413. cp->u.sldr.u.sldr = new Fl_Value_Slider(x,y,w,h);
  414. cp->u.sldr.val = static_cast<Fl_Valuator*>(cp->u.sldr.u.sldr);
  415. cp->u.sldr.u.sldr->type(cp->mstrFl ? FL_VERT_NICE_SLIDER : FL_HOR_NICE_SLIDER);
  416. break;
  417. case kNumberDuiId:
  418. cp->u.sldr.u.numb = new Fl_Value_Input(x,y,w/2,h);
  419. cp->u.sldr.u.numb->when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE );
  420. cp->u.sldr.val = static_cast<Fl_Valuator*>(cp->u.sldr.u.numb);
  421. break;
  422. }
  423. _insertNewCtl(cp, m, cp->u.sldr.val, cp->u.sldr.varIdArray, kSldrVarCnt );
  424. }
  425. // handle slider value msg's arriving from the engine
  426. void kcApp::_setSldrValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  427. {
  428. unsigned i=0;
  429. Fl_Valuator* sp = cp->u.sldr.val;
  430. for(i=0; i<kSldrVarCnt; ++i)
  431. if( cp->u.sldr.varIdArray[i] == instVarId )
  432. {
  433. switch(i)
  434. {
  435. case kSldrMinArgIdx:
  436. sp->minimum(cmDsvGetDouble(vp));
  437. //sp->step((sp->maximum()-sp->minimum())/sp->w());
  438. break;
  439. case kSldrMaxArgIdx:
  440. sp->maximum(cmDsvGetDouble(vp));
  441. //sp->step((sp->maximum()-sp->minimum())/sp->w());
  442. break;
  443. case kSldrStpArgIdx:
  444. sp->step(cmDsvGetDouble(vp));
  445. break;
  446. case kSldrValArgIdx:
  447. sp->value(cmDsvGetDouble(vp));
  448. break;
  449. case kSldrLblArgIdx:
  450. {
  451. int ww=0,hh=0;
  452. if( cmDsvStrcz(vp) == NULL )
  453. {
  454. sp->label(NULL);
  455. sp->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER );
  456. }
  457. else
  458. {
  459. sp->copy_label( cmDsvStrcz(vp) );
  460. sp->align(FL_ALIGN_RIGHT);
  461. }
  462. if( cp->typeId == kSldrTypeId )
  463. {
  464. sp->measure_label(ww,hh);
  465. sp->resize( sp->x(), sp->y(), sp->w() - ww, sp->h());
  466. sp->redraw();
  467. }
  468. }
  469. break;
  470. default:
  471. { assert(0); }
  472. }
  473. break;
  474. }
  475. }
  476. void kcApp::_createText( const cmDspUiHdr_t* m )
  477. {
  478. int x,y,w=0,h=0;
  479. ctl_t* cp = _createCtl(m, kTextTypeId, x,y,w,h );
  480. cp->u.text.text = new Fl_Input(x,y,w,h);
  481. cp->u.text.text->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY | FL_WHEN_NOT_CHANGED);
  482. _insertNewCtl(cp, m, cp->u.text.text, cp->u.text.varIdArray, kTextVarCnt );
  483. }
  484. void kcApp::_setTextValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  485. {
  486. unsigned i=0;
  487. Fl_Input* tp = cp->u.text.text;
  488. for(i=0; i<kTextVarCnt; ++i)
  489. if( cp->u.text.varIdArray[i] == instVarId )
  490. {
  491. switch(i)
  492. {
  493. case kTextValArgIdx:
  494. tp->value( cmDsvStrcz(vp));
  495. break;
  496. case kTextLblArgIdx:
  497. {
  498. const char* lbl = cmDsvStrcz(vp);
  499. if( lbl == NULL )
  500. tp->label(NULL);
  501. else
  502. tp->copy_label( lbl );
  503. tp->align(FL_ALIGN_RIGHT);
  504. tp->resize( tp->x(), tp->y(), tp->w()/2, tp->h());
  505. tp->redraw();
  506. }
  507. break;
  508. default:
  509. { assert(0); }
  510. }
  511. }
  512. }
  513. void kcApp::_createFnameCtl( const cmDspUiHdr_t* m )
  514. {
  515. int x,y,w=0,h=0;
  516. ctl_t* cp = _createCtl(m, kFnamTypeId, x,y,w,h );
  517. cp->u.fnam.fnam = new Fl_File_Btn(x,y,w,h);
  518. _insertNewCtl(cp, m, cp->u.fnam.fnam, cp->u.fnam.varIdArray, kFnamVarCnt );
  519. }
  520. void kcApp::_setFnamValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  521. {
  522. unsigned i=0;
  523. Fl_File_Btn* bp = cp->u.fnam.fnam;
  524. for(i=0; i<kFnamVarCnt; ++i)
  525. if( cp->u.fnam.varIdArray[i] == instVarId )
  526. {
  527. switch(i)
  528. {
  529. case kFnamValArgIdx:
  530. assert( cmDsvIsType( vp, kStrzDsvFl ) );
  531. bp->filename( cmDsvStrcz(vp) );
  532. bp->redraw();
  533. break;
  534. case kFnamPatArgIdx:
  535. assert( cmDsvIsType( vp, kStrzDsvFl ) );
  536. bp->pattern_string( cmDsvStrcz(vp) );
  537. break;
  538. case kFnamDirArgIdx:
  539. bp->type( cmDsvBool(vp) ? Fl_File_Btn::kDir_Type_Id : Fl_File_Btn::kFile_Type_Id );
  540. break;
  541. default:
  542. { assert(0); }
  543. }
  544. }
  545. }
  546. void kcApp::_createMlistCtl( const cmDspUiHdr_t* m )
  547. {
  548. const unsigned* varIdArray = cmDsvUIntCMtx(&m->value);
  549. assert( varIdArray != NULL && cmDsvEleCount(&m->value)==kMlstVarCnt);
  550. int x,y,w=0;
  551. int h = varIdArray[kMlstHgtArgIdx];
  552. bool menuBtnFl = h==0;
  553. h = menuBtnFl ? kMenuH : kMenuH * h;
  554. ctl_t* cp = _createCtl(m, kMlstTypeId, x,y,w,h );
  555. Fl_Widget* wdgt;
  556. if(menuBtnFl)
  557. {
  558. cp->u.mlst.mlst = NULL;
  559. wdgt = cp->u.mlst.mbtn = new Fl_Menu_Button(x,y,w,h);
  560. }
  561. else
  562. {
  563. cp->u.mlst.mbtn = NULL;
  564. wdgt = cp->u.mlst.mlst = new Fl_Select_Browser(x,y,w,h);
  565. }
  566. _insertNewCtl(cp, m, wdgt, cp->u.mlst.varIdArray, kMlstVarCnt );
  567. }
  568. kcApp::kcKmRC_t kcApp::_loadMlist( ctl_t* cp, const cmJsonNode_t* np )
  569. {
  570. assert( cmJsonIsArray(np) );
  571. kcKmRC_t rc = kOkKmRC;
  572. unsigned n = cmJsonChildCount(np);
  573. unsigned ri = 0;
  574. // empty the ctl data list
  575. if( cp->u.mlst.mbtn == NULL )
  576. cp->u.mlst.mlst->clear();
  577. else
  578. cp->u.mlst.mbtn->clear();
  579. // for each element (row) in the JSON array
  580. for(ri=0; ri<n && rc==kOkKmRC; ++ri)
  581. {
  582. const cmJsonNode_t* cnp = cmJsonArrayElementC(np,ri);
  583. unsigned m = cmJsonChildCount(cnp);
  584. unsigned bufCharCnt = 511;
  585. cmChar_t buf[ bufCharCnt + 1 ]; // buffer to hold one row of text
  586. cmChar_t* bbp = buf;
  587. cmChar_t* bep = bbp + bufCharCnt;
  588. unsigned j;
  589. buf[0] = 0;
  590. // for each element (column) of row i
  591. for(j=0; j<m; ++j)
  592. {
  593. const cmJsonNode_t* ep = cmJsonArrayElementC(cnp,j);
  594. cmJsRC_t jsRC;
  595. // convert the element to a string
  596. if( (jsRC = cmJsonLeafToString( ep, bbp, bep - bbp )) != kOkJsRC )
  597. {
  598. switch(jsRC)
  599. {
  600. case kBufTooSmallJsRC:
  601. rc = cmErrMsg(&_ctx->err,kMlistLoadFailKmRC,"The msg list line character buffer is too small at JSON array element index %i.",ri);
  602. break;
  603. case kInvalidNodeTypeJsRC:
  604. rc = cmErrMsg(&_ctx->err,kMlistLoadFailKmRC,"The msg list array element at index %i is not a JSON leaf node.",ri);
  605. break;
  606. default:
  607. rc = cmErrMsg(&_ctx->err,kMlistLoadFailKmRC,"JSON to msg list text conversion failed on array element %i.",ri);
  608. break;
  609. }
  610. break;
  611. }
  612. bbp = buf + strlen(buf);
  613. assert(bbp <= bep);
  614. // add the tab column marker
  615. if( j+1 < m )
  616. {
  617. if( bep - bbp < 1 )
  618. rc = cmErrMsg(&_ctx->err,kMlistLoadFailKmRC,"The msg list line buffer is too small.");
  619. else
  620. {
  621. *bbp++ = '\t';
  622. *bbp = 0;
  623. }
  624. }
  625. }
  626. // insert the text for row i and skip the title row
  627. // See the _setMListValue() and _ctl_cb() for the associated index incr/decr.
  628. // so that the engine list indexes and UI list indexes match
  629. if( rc == kOkKmRC && ri > 0)
  630. {
  631. if( cp->u.mlst.mbtn==NULL)
  632. cp->u.mlst.mlst->add(buf);
  633. else
  634. cp->u.mlst.mbtn->add(buf);
  635. }
  636. }
  637. if( rc == kOkKmRC )
  638. if( cp->u.mlst.mbtn != NULL )
  639. {
  640. if( cp->u.mlst.sel < cp->u.mlst.mbtn->size() )
  641. cp->u.mlst.mbtn->label(cp->u.mlst.mbtn->text(cp->u.mlst.sel));;
  642. }
  643. return rc;
  644. }
  645. void kcApp::_setMlistValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  646. {
  647. unsigned i=0;
  648. for(i=0; i<kMlstVarCnt; ++i)
  649. if( cp->u.mlst.varIdArray[i] == instVarId )
  650. {
  651. switch(i)
  652. {
  653. case kMlstHgtArgIdx:
  654. break;
  655. case kMlstSelArgIdx:
  656. {
  657. unsigned idx = cmDsvUInt(vp);
  658. // decr. to account for skipping title row
  659. // (see the complementary incrementn in _ctl_cb())
  660. if( idx > 0 && cp->u.mlst.mbtn!=NULL)
  661. --idx;
  662. if( cp->u.mlst.mbtn==NULL)
  663. cp->u.mlst.mlst->value(idx);
  664. else
  665. {
  666. cp->u.mlst.sel = idx;
  667. if( cp->u.mlst.sel < cp->u.mlst.mbtn->size() )
  668. {
  669. cp->u.mlst.mbtn->value(cp->u.mlst.sel);
  670. cp->u.mlst.mbtn->label( cp->u.mlst.mbtn->text(cp->u.mlst.sel) );
  671. }
  672. }
  673. cp->wdgtPtr->redraw();
  674. }
  675. break;
  676. case kMlstLstArgIdx:
  677. _loadMlist( cp, cmDsvJson(vp) );
  678. break;
  679. default:
  680. { assert(0); }
  681. }
  682. }
  683. }
  684. // create a meter ctl at the request of the engine
  685. void kcApp::_createMeter( const cmDspUiHdr_t* m )
  686. {
  687. int x,y,w=0,h=15;
  688. ctl_t* cp = _createCtl(m,kMetrTypeId, x,y,w,h);
  689. if( cp->mstrFl )
  690. cp->u.metr.prog = new Fl_Vert_Progress(x,y,w,h);
  691. else
  692. cp->u.metr.prog = new Fl_Progress(x,y,w,h);
  693. cp->u.metr.prog->color( fl_rgb_color((unsigned char)256),fl_rgb_color((unsigned char)128));
  694. _insertNewCtl(cp,m,cp->u.metr.prog,cp->u.metr.varIdArray,kMetrVarCnt);
  695. }
  696. // handle meter value msg's arriving from the engine
  697. void kcApp::_setMeterValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  698. {
  699. unsigned i = 0;
  700. Fl_Progress* sp = cp->u.metr.prog;
  701. bool redrawFl = false;
  702. for(i=0; i<kMetrVarCnt; ++i)
  703. if( cp->u.metr.varIdArray[i] == instVarId )
  704. {
  705. switch(i)
  706. {
  707. case kMetrMinArgIdx:
  708. sp->minimum(cmDsvGetDouble(vp));
  709. redrawFl = true;
  710. break;
  711. case kMetrMaxArgIdx:
  712. sp->maximum(cmDsvGetDouble(vp));
  713. redrawFl = true;
  714. break;
  715. case kMetrValArgIdx:
  716. {
  717. double v = cmDsvGetDouble(vp);
  718. if( sp->value() != v )
  719. {
  720. sp->value(v);
  721. redrawFl = true;
  722. }
  723. break;
  724. }
  725. case kMetrLblArgIdx:
  726. {
  727. int ww=0,hh=0;
  728. sp->copy_label( cmDsvStrcz(vp) );
  729. sp->align(FL_ALIGN_RIGHT);
  730. sp->measure_label(ww,hh);
  731. sp->resize( sp->x(), sp->y(), sp->w() - ww, sp->h());
  732. redrawFl = true;
  733. }
  734. break;
  735. default:
  736. { assert(0); }
  737. }
  738. break;
  739. }
  740. if( redrawFl )
  741. sp->redraw();
  742. }
  743. // create a button ctl at the request of the engine
  744. void kcApp::_createButton( const cmDspUiHdr_t* m )
  745. {
  746. int x,y,w=0,h=0;
  747. ctl_t* cp = _createCtl(m,kButnTypeId, x,y,w,h);
  748. cp->u.butn.butn = new Fl_Button(x,y,w,h);
  749. _insertNewCtl(cp,m,cp->u.butn.butn,cp->u.butn.varIdArray,kButnVarCnt);
  750. }
  751. // handle button value msg's arriving from the engine
  752. void kcApp::_setButtonValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  753. {
  754. unsigned i = 0;
  755. Fl_Button* sp = cp->u.butn.butn;
  756. bool redrawFl = false;
  757. for(i=0; i<kButnVarCnt; ++i)
  758. if( cp->u.butn.varIdArray[i] == instVarId )
  759. {
  760. switch(i)
  761. {
  762. case kButnValArgIdx:
  763. cp->u.butn.val = cmDsvGetDouble(vp);
  764. break;
  765. case kButnLblArgIdx:
  766. {
  767. sp->copy_label( cmDsvStrcz(vp) );
  768. redrawFl = true;
  769. }
  770. break;
  771. default:
  772. { assert(0); }
  773. }
  774. break;
  775. }
  776. if( redrawFl )
  777. sp->redraw();
  778. }
  779. // create a button ctl at the request of the engine
  780. void kcApp::_createCheck( const cmDspUiHdr_t* m )
  781. {
  782. int x,y,w=0,h=0;
  783. ctl_t* cp = _createCtl(m,kChckTypeId, x,y,w,h);
  784. cp->u.chck.chck = new Fl_Check_Button(x,y,w,h);
  785. _insertNewCtl(cp,m,cp->u.chck.chck,cp->u.chck.varIdArray,kChckVarCnt);
  786. }
  787. // handle check button value msg's arriving from the engine
  788. void kcApp::_setCheckValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  789. {
  790. unsigned i = 0;
  791. Fl_Button* sp = cp->u.chck.chck;
  792. bool redrawFl = false;
  793. for(i=0; i<kChckVarCnt; ++i)
  794. if( cp->u.chck.varIdArray[i] == instVarId )
  795. {
  796. switch(i)
  797. {
  798. case kChckValArgIdx:
  799. cp->u.chck.val = cmDsvGetDouble(vp);
  800. cp->u.chck.chck->value(cmDsvGetDouble(vp)>0);
  801. break;
  802. case kChckLblArgIdx:
  803. {
  804. int ww=0,hh=0;
  805. sp->copy_label( cmDsvStrcz(vp) );
  806. sp->align(FL_ALIGN_RIGHT);
  807. sp->measure_label(ww,hh);
  808. sp->resize( sp->x(), sp->y(), sp->w() - ww, sp->h());
  809. redrawFl = true;
  810. }
  811. break;
  812. default:
  813. { assert(0); }
  814. }
  815. break;
  816. }
  817. if( redrawFl )
  818. sp->redraw();
  819. }
  820. void kcApp::_createLabel( const cmDspUiHdr_t* m )
  821. {
  822. int x,y,w=0,h=0;
  823. ctl_t* cp = _createCtl(m,kLablTypeId, x,y,w,h);
  824. cp->u.labl.box = new Fl_Box(x,y,w,h);
  825. _insertNewCtl(cp,m,cp->u.labl.box,cp->u.labl.varIdArray,kLablVarCnt);
  826. }
  827. void kcApp::_setLabelValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  828. {
  829. unsigned i = 0;
  830. Fl_Box* sp = cp->u.labl.box;
  831. bool redrawFl = false;
  832. for(i=0; i<kLablVarCnt; ++i)
  833. if( cp->u.labl.varIdArray[i] == instVarId )
  834. {
  835. switch(i)
  836. {
  837. case kLablValArgIdx:
  838. sp->copy_label(cmDsvStrcz(vp));
  839. redrawFl = true;
  840. break;
  841. case kLablAlignArgIdx:
  842. switch( cmDsvUInt(vp) )
  843. {
  844. case kRightAlignDuiId:
  845. sp->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE);
  846. break;
  847. case kLeftAlignDuiId:
  848. sp->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
  849. break;
  850. case kCenterAlignDuiId:
  851. sp->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
  852. break;
  853. default:
  854. { assert(0); }
  855. }
  856. redrawFl = true;
  857. break;
  858. default:
  859. {assert(0);}
  860. }
  861. }
  862. if( redrawFl )
  863. sp->redraw();
  864. }
  865. void kcApp::_createTmln( const cmDspUiHdr_t* m )
  866. {
  867. int x,y,w=0,h=0;
  868. page_t* pg = _createPage("TimeLine");
  869. ctl_t* cp = _createCtl(m, kTmlnTypeId, x,y,w,h, true );
  870. w = pg->grp->w();
  871. h = pg->grp->h();
  872. // currently we only support one score control because
  873. // we have not yet implmenented a method of providing
  874. // timer callbacks to a list of UI controls
  875. if( _tlCtl != NULL )
  876. cp->u.tmln.tlctl = _tlCtl;
  877. else
  878. {
  879. _tlCtl = new tlCtl(_ctx,this,_menu,this);
  880. cp->u.tmln.tlctl = _tlCtl;
  881. }
  882. Fl_Widget* wdgt = cp->u.tmln.tlctl->initTimeLineCtlr(x,y,w,h);
  883. _insertNewCtl(cp,m,wdgt,cp->u.tmln.varIdArray,kTmlnVarCnt);
  884. }
  885. void kcApp::_setTmlnValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  886. {
  887. unsigned i=0;
  888. for(i=0; i<kTmlnVarCnt; ++i)
  889. if( cp->u.tmln.varIdArray[i] == instVarId )
  890. {
  891. switch(i)
  892. {
  893. case kTmlnFileArgIdx:
  894. {
  895. const char* fn;
  896. if((fn = cmDsvStrcz(vp)) != NULL )
  897. {
  898. cp->u.tmln.tlctl->openTlFile(fn);
  899. //cp->u.tmln.tlctl->redraw();
  900. }
  901. }
  902. break;
  903. case kTmlnPathArgIdx:
  904. {
  905. const char* path;
  906. if((path = cmDsvStrcz(vp)) != NULL )
  907. {
  908. cp->u.tmln.tlctl->setAudioFilePath(path);
  909. }
  910. }
  911. break;
  912. case kTmlnSelArgIdx:
  913. //tp->value( cmDsvStrcz(vp));
  914. break;
  915. case kTmlnCursArgIdx:
  916. cp->u.tmln.tlctl->setAudioFileCursor(cmDsvUInt(vp));
  917. break;
  918. default:
  919. { assert(0); }
  920. }
  921. }
  922. }
  923. void kcApp::_createScor( const cmDspUiHdr_t* m )
  924. {
  925. int x,y,w=0,h=0;
  926. page_t* pg = _createPage("Score");
  927. ctl_t* cp = _createCtl(m, kScorTypeId, x,y,w,h, true );
  928. w = pg->grp->w();
  929. h = pg->grp->h();
  930. // currently we only support one score control because
  931. // we have not yet implmenented a method of providing
  932. // timer callbacks to a list of UI controls
  933. if( _tlCtl != NULL )
  934. cp->u.scor.tlctl = _tlCtl;
  935. else
  936. {
  937. _tlCtl = new tlCtl(_ctx,this,_menu,this);
  938. cp->u.scor.tlctl = _tlCtl;
  939. cp->u.scor.smpIdx = cmInvalidIdx;
  940. }
  941. Fl_Widget* wdgt = cp->u.scor.tlctl->initScoreCtlr(x,y,w,h);
  942. _insertNewCtl(cp,m,wdgt,cp->u.scor.varIdArray,kScorVarCnt);
  943. }
  944. void kcApp::_setScorValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp )
  945. {
  946. unsigned i=0;
  947. //tlCtl* tp = cp->u.scor.tlctl;
  948. for(i=0; i<kScorVarCnt; ++i)
  949. if( cp->u.scor.varIdArray[i] == instVarId )
  950. {
  951. switch(i)
  952. {
  953. case kScorSelArgIdx:
  954. //tp->value( cmDsvStrcz(vp));
  955. break;
  956. case kScorFileArgIdx:
  957. {
  958. const char* fn;
  959. if((fn = cmDsvStrcz(vp)) != NULL )
  960. {
  961. cp->u.scor.tlctl->openScoreFile(fn);
  962. //cp->u.scor.tlctl->redraw();
  963. }
  964. }
  965. break;
  966. case kScorSmpIdxArgIdx:
  967. cp->u.scor.smpIdx = cmDsvUInt(vp);
  968. break;
  969. case kScorPitchArgIdx:
  970. cp->u.scor.pitch = cmDsvUInt(vp);
  971. break;
  972. case kScorVelArgIdx:
  973. cp->u.scor.vel = cmDsvUInt(vp);
  974. break;
  975. case kScorEvtIdxArgIdx:
  976. cp->u.scor.evtIdx = cmDsvUInt(vp);
  977. break;
  978. case kScorDynArgIdx:
  979. {
  980. assert(cp->u.scor.evtIdx!=cmInvalidIdx);
  981. _tlCtl->setScoreDynLevel(cp->u.scor.evtIdx,cmDsvUInt(vp));
  982. cp->u.scor.evtIdx = cmInvalidIdx;
  983. }
  984. break;
  985. case kScorLocIdxArgIdx:
  986. {
  987. assert( cp->u.scor.smpIdx != cmInvalidIdx );
  988. cp->u.scor.locIdx = cmDsvUInt(vp);
  989. _tlCtl->setScoreLocation(cp->u.scor.locIdx,cp->u.scor.smpIdx,cp->u.scor.pitch,cp->u.scor.vel);
  990. cp->u.scor.smpIdx = cmInvalidIdx;
  991. }
  992. break;
  993. case kScorValTypeArgIdx:
  994. cp->u.scor.varId = cmDsvUInt(vp);
  995. break;
  996. case kScorValueArgIdx:
  997. _tlCtl->setScoreVarValue(cp->u.scor.locIdx,cp->u.scor.varId, cmDsvDouble(vp));
  998. break;
  999. default:
  1000. { assert(0); }
  1001. }
  1002. }
  1003. }
  1004. void kcApp::_newColumn( const cmDspUiHdr_t* m )
  1005. {
  1006. _incrColW = cmDsvGetUInt(&m->value);
  1007. if( _incrColW == 0 )
  1008. _incrColW = 200;
  1009. }
  1010. void kcApp::_insertAudioSysCfgLabel(unsigned long idx, const char* label)
  1011. {
  1012. if( idx == 0 )
  1013. _as_btn->clear();
  1014. _as_btn->add(label,0,NULL,(void*)idx,0);
  1015. }
  1016. void kcApp::_insertDeviceLabel( unsigned long devIdx, bool inputFl, const cmChar_t* label )
  1017. {
  1018. Fl_Menu_Button* bp = inputFl ? _ai_btn : _ao_btn;
  1019. // ??? if( idx == 0 )
  1020. // bp->clear();
  1021. bp->add(label,0,NULL,(void*)devIdx,0);
  1022. }
  1023. void kcApp::_insertProgramLabel( unsigned long idx, const cmChar_t* label )
  1024. {
  1025. if( idx == 0 )
  1026. _pgm_btn->clear();
  1027. _pgm_btn->add(label,0,NULL,(void*)idx,0);
  1028. }
  1029. void kcApp::_insertSubSysCnt( unsigned long subSysCnt )
  1030. {
  1031. long unsigned i;
  1032. int bufByteCnt = 15;
  1033. char buf[bufByteCnt+1];
  1034. for(i=0; i<subSysCnt+1; ++i)
  1035. {
  1036. const char* label;
  1037. unsigned long id;
  1038. if( i==0 )
  1039. {
  1040. label = "All";
  1041. id = cmInvalidIdx;
  1042. }
  1043. else
  1044. {
  1045. snprintf(buf,bufByteCnt,"%li",i);
  1046. label = buf;
  1047. id = i-1;
  1048. }
  1049. _ss_btn->add(label,0,NULL,(void*)id);
  1050. }
  1051. _ss_btn->value(0);
  1052. _ss_btn->copy_label( _ss_btn->mvalue()->label() );
  1053. }
  1054. unsigned kcApp::_getCurAudioSubSysIdx()
  1055. {
  1056. const Fl_Menu_Item* mip;
  1057. unsigned retVal = 0;
  1058. if( (mip = _ss_btn->mvalue()) != NULL)
  1059. retVal = mip->argument();
  1060. return retVal;
  1061. }
  1062. void kcApp::_setMenuButton( Fl_Menu_Button* b, unsigned value, const char* dfltLabel )
  1063. {
  1064. const Fl_Menu_Item* mip;
  1065. bool fl = value != cmInvalidIdx;
  1066. // if value is a valid menu index then make it the current menu selection
  1067. if( fl )
  1068. b->value(value);
  1069. // get the new current menu item and set its label
  1070. if( (mip = b->mvalue()) != NULL )
  1071. b->copy_label( fl ? mip->label() : dfltLabel );
  1072. }
  1073. void kcApp::_setDeviceMenuButton( unsigned asSubIdx, bool inputFl, unsigned devIdx )
  1074. {
  1075. // don't set the device name if the currenly selected sub-system is not the
  1076. // same as the one the device is assigned to
  1077. if( _getCurAudioSubSysIdx() != asSubIdx )
  1078. return;
  1079. Fl_Menu_Button* mbp = inputFl ? _ai_btn : _ao_btn;
  1080. const Fl_Menu_Item* map = mbp->menu();
  1081. unsigned n = mbp->size();
  1082. unsigned i;
  1083. char* di = 0; di += devIdx; // BEWARE: devious int to ptr trick
  1084. for(i=0; i<n; ++i)
  1085. if( map[i].user_data() == di )
  1086. break;
  1087. if( i < n )
  1088. {
  1089. _setMenuButton(mbp,i,"<not found>");
  1090. }
  1091. }
  1092. void kcApp::_setSampleRateBtn( unsigned value )
  1093. {
  1094. unsigned i;
  1095. unsigned n = _sr_btn->size();
  1096. for(i=0; i<n-1; ++i)
  1097. {
  1098. if( _sr_btn->menu()[i].argument() == (int)value )
  1099. {
  1100. _sr_btn->value(i);
  1101. _sr_btn->copy_label( _sr_btn->mvalue()->label() );
  1102. return;
  1103. }
  1104. }
  1105. _sr_btn->copy_label("Sample Rate?");
  1106. }
  1107. void kcApp::_updateMeters( unsigned asSubIdx, unsigned devIdx, unsigned inFl, const double* meterArray, unsigned meterCnt )
  1108. {
  1109. unsigned i;
  1110. for(i=0; i<meterCnt; ++i)
  1111. {
  1112. ctl_t* cp;
  1113. cmDspValue_t v;
  1114. unsigned instId = cmAudioSysFormUiInstId(devIdx,i,inFl,kMeterUiAsId);
  1115. if((cp = _findCtl(instId,asSubIdx,true)) != NULL )
  1116. {
  1117. cmDsvSetDouble(&v,meterArray[i]);
  1118. _setMeterValue(cp, kMetrValArgIdx, &v);
  1119. }
  1120. }
  1121. }
  1122. void kcApp::_printStatusCounts()
  1123. {
  1124. const ss_t* ssp = _ssArray;
  1125. printf("Upd:%i Wake:%i Msg:%i Audio:%i\n",ssp->cnt[kUpdateSsIdx],ssp->cnt[kWakeupSsIdx],ssp->cnt[kMsgSsIdx],ssp->cnt[kAudioCbSsIdx]);
  1126. }
  1127. void kcApp::_updateSsStatusIndicator( unsigned asSubIdx, unsigned indicatorIdx, unsigned cnt )
  1128. {
  1129. ss_t* ss = _ssArray + asSubIdx;
  1130. float val = ss->cnt[indicatorIdx] != cnt;
  1131. ss->cnt[indicatorIdx] = cnt;
  1132. if( ss->prog[indicatorIdx]->value() != val )
  1133. {
  1134. ss->prog[indicatorIdx]->value(val);
  1135. ss->prog[indicatorIdx]->redraw();
  1136. }
  1137. }
  1138. void kcApp::_handleStatusMsg(const cmAudioSysStatus_t* st, const double* iMeterArray, const double* oMeterArray )
  1139. {
  1140. //unsigned asSubIdx = ((const unsigned*)msgBuf)[0];
  1141. //const cmAudioSysStatus_t* st = (const cmAudioSysStatus_t*)(msgBuf + (2 * sizeof(unsigned)));
  1142. //const double* iMeterArray = (const double*)(st + 1);
  1143. //const double* oMeterArray = iMeterArray + st->iMeterCnt;
  1144. _updateMeters(st->asSubIdx, st->iDevIdx,1,iMeterArray,st->iMeterCnt);
  1145. _updateMeters(st->asSubIdx, st->oDevIdx,0,oMeterArray,st->oMeterCnt);
  1146. assert( st->asSubIdx < _ssCnt );
  1147. _updateSsStatusIndicator(st->asSubIdx, kUpdateSsIdx, st->updateCnt );
  1148. _updateSsStatusIndicator(st->asSubIdx, kWakeupSsIdx, st->wakeupCnt );
  1149. _updateSsStatusIndicator(st->asSubIdx, kMsgSsIdx, st->msgCbCnt );
  1150. _updateSsStatusIndicator(st->asSubIdx, kAudioCbSsIdx,st->audioCbCnt );
  1151. }
  1152. void kcApp::_clearStatusIndicators()
  1153. {
  1154. for(unsigned i=0; i<_ssCnt; ++i)
  1155. {
  1156. _updateSsStatusIndicator(i, kUpdateSsIdx, _ssArray[i].cnt[kUpdateSsIdx] );
  1157. _updateSsStatusIndicator(i, kWakeupSsIdx, _ssArray[i].cnt[kWakeupSsIdx] );
  1158. _updateSsStatusIndicator(i, kMsgSsIdx, _ssArray[i].cnt[kMsgSsIdx] );
  1159. _updateSsStatusIndicator(i, kAudioCbSsIdx,_ssArray[i].cnt[kAudioCbSsIdx] );
  1160. }
  1161. }
  1162. // Create a master control UI msg and send it to _handleUiMsg(). This function is intended to
  1163. // mimic the reception of a cmDspUiHdr_t msg from the audio system. It is used to create
  1164. // and send values to the controls on the master page.
  1165. void kcApp::_sendMasterUiMsg( unsigned asSubIdx, unsigned selId, unsigned instId, unsigned instVarId, const cmDspValue_t* vp )
  1166. {
  1167. // Determine the size of the message buffer
  1168. unsigned valByteCnt = cmDsvSerialDataByteCount(vp);
  1169. unsigned bufByteCnt = sizeof(cmDspUiHdr_t) + valByteCnt;
  1170. char buf[ bufByteCnt ];
  1171. cmDspUiHdr_t* h = (cmDspUiHdr_t*)buf;
  1172. h->asSubIdx = asSubIdx;
  1173. h->uiId = cmInvalidId; // the uiId field of master controls is always set to cmInvalidId
  1174. h->selId = selId;
  1175. h->flags = 0;
  1176. h->instId = instId;
  1177. h->instVarId = instVarId;
  1178. // Serialize 'v' into the buffer beginning at the address of h->value.
  1179. // (this function relies on the 'hdr.value' field being the last field in 'h')
  1180. cmDsvSerialize( vp, &h->value, sizeof(cmDspValue_t) + valByteCnt);
  1181. _handleUiMsg(h);
  1182. }
  1183. // Send a value to a control on the master page.
  1184. void kcApp::_sendMasterUiValue( unsigned asSubIdx, unsigned instId, const double* v, unsigned vn, const cmChar_t* text )
  1185. {
  1186. cmDspValue_t val;
  1187. unsigned i;
  1188. for(i=0; i<vn; ++i)
  1189. {
  1190. cmDsvSetDouble(&val,v[i]);
  1191. _sendMasterUiMsg(asSubIdx, kValueDuiId, instId, i, &val );
  1192. }
  1193. if( text != NULL )
  1194. {
  1195. cmDsvSetStrcz(&val,text);
  1196. _sendMasterUiMsg(asSubIdx, kValueDuiId, instId, i, &val );
  1197. }
  1198. }
  1199. // Create a control on the master page.
  1200. void kcApp::_createMasterCtl( unsigned asSubIdx, unsigned selId, unsigned instId, unsigned varCnt, const double* dv, unsigned dn, const cmChar_t* label)
  1201. {
  1202. // Create the control variable id array.
  1203. // This array gives the id's used to identify each control variable.
  1204. unsigned varIdArray[ varCnt ];
  1205. unsigned i;
  1206. cmDspValue_t v;
  1207. // Set the var id's for master controls to be the same as the var indexes.
  1208. for(i=0; i<varCnt; ++i)
  1209. varIdArray[i] = i;
  1210. // Encode varIdArray[] as a cmDsvValue.
  1211. cmDsvSetUIntMtx(&v,varIdArray,varCnt,1);
  1212. // create the control
  1213. _sendMasterUiMsg(asSubIdx, selId, instId, cmInvalidId, &v );
  1214. // set the controls initial configuration
  1215. _sendMasterUiValue(asSubIdx, instId, dv, dn, label );
  1216. }
  1217. void kcApp::_handleSsInitMsg( const cmAudioSysSsInitMsg_t* m, const cmChar_t* inDevLabel, const cmChar_t* outDevLabel )
  1218. {
  1219. unsigned i,j;
  1220. if( _ssCnt == 0 )
  1221. {
  1222. _clearSsArray();
  1223. _ssCnt = m->asSubCnt;
  1224. _ssArray = new ss_t[ _ssCnt ];
  1225. }
  1226. assert( m->asSubIdx < _ssCnt );
  1227. ss_t* ss = _ssArray + m->asSubIdx;
  1228. int x = 20;
  1229. int y = 30 + kMenuH;
  1230. int w = 80;
  1231. int h = 20;
  1232. char lblArray[][10] = { "Update","Wakeup","Mesg","Audio" };
  1233. // create the sub-system status indicators
  1234. for(i=0; i<kProgSsCnt; ++i)
  1235. {
  1236. Fl_Progress* prog = new Fl_Progress(x,y,w,h,NULL);
  1237. prog->color( FL_RED, FL_GREEN );
  1238. prog->minimum(0);
  1239. prog->maximum(1);
  1240. prog->copy_label(lblArray[i]);
  1241. _mstr_grp->add(prog);
  1242. ss->cnt[i] = 0;
  1243. ss->prog[i] = prog;
  1244. x += ss->prog[i]->w() + 4;
  1245. }
  1246. for(i=0; i<2; ++i)
  1247. {
  1248. unsigned inFl = i==0;
  1249. unsigned chCnt = inFl ? m->inChCnt : m->outChCnt;
  1250. unsigned devIdx = inFl ? m->inDevIdx : m->outDevIdx;
  1251. double zero = 0;
  1252. for(j=0; j<chCnt; ++j)
  1253. {
  1254. // there are limits on the ranges of the dev and ch due to the need to pack dev/ch/infl/ctl into a 32 bit int.
  1255. assert( devIdx < 0xffff && j < 0x0fff);
  1256. unsigned instId = cmAudioSysFormUiInstId(devIdx,j,inFl,0);
  1257. //printf("ssi:%i instId:0x%x\n",m->asSubIdx,instId+kMeterUiAsId);
  1258. // create the volume slider
  1259. double sv[] = { 3, 0, 0.01, 1 };
  1260. unsigned sn = sizeof(sv)/sizeof(sv[0]);
  1261. _createMasterCtl( m->asSubIdx, kSliderDuiId, instId + kSliderUiAsId, kSldrVarCnt, sv, sn, NULL);
  1262. // create the meter
  1263. double mv[] = { 0, 1.0, 0 };
  1264. unsigned mn = sizeof(mv)/sizeof(mv[0]);
  1265. _createMasterCtl( m->asSubIdx, kMeterDuiId, instId + kMeterUiAsId, kMetrVarCnt, mv, mn, NULL);
  1266. // create the mute button
  1267. _createMasterCtl( m->asSubIdx, kCheckDuiId, instId + kMuteUiAsId, kChckVarCnt, &zero, 1, "M");
  1268. // create the tone button
  1269. _createMasterCtl( m->asSubIdx, kCheckDuiId, instId + kToneUiAsId, kChckVarCnt, &zero, 1, "T");
  1270. // create the pass button
  1271. _createMasterCtl( m->asSubIdx, kCheckDuiId, instId + kPassUiAsId, kChckVarCnt, &zero, 1, "P");
  1272. }
  1273. }
  1274. }
  1275. // handle kValueDuiId messages coming from the engine
  1276. void kcApp::_onRecvValue( const cmDspUiHdr_t* m )
  1277. {
  1278. ctl_t* cp;
  1279. if((cp = _findCtl(m->instId,m->asSubIdx,m->uiId==cmInvalidId)) == NULL )
  1280. return;
  1281. switch( cp->typeId )
  1282. {
  1283. case kNumbTypeId:
  1284. case kSldrTypeId:
  1285. _setSldrValue(cp, m->instVarId, &m->value );
  1286. break;
  1287. case kTextTypeId:
  1288. _setTextValue(cp, m->instVarId, &m->value );
  1289. break;
  1290. case kButnTypeId:
  1291. _setButtonValue(cp, m->instVarId, &m->value);
  1292. break;
  1293. case kChckTypeId:
  1294. _setCheckValue(cp, m->instVarId, &m->value);
  1295. break;
  1296. case kLablTypeId:
  1297. _setLabelValue(cp, m->instVarId, &m->value);
  1298. break;
  1299. case kFnamTypeId:
  1300. _setFnamValue(cp, m->instVarId, &m->value);
  1301. break;
  1302. case kMlstTypeId:
  1303. _setMlistValue(cp, m->instVarId, &m->value);
  1304. break;
  1305. case kMetrTypeId:
  1306. _setMeterValue(cp, m->instVarId, &m->value);
  1307. break;
  1308. case kTmlnTypeId:
  1309. _setTmlnValue(cp, m->instVarId, &m->value);
  1310. break;
  1311. case kScorTypeId:
  1312. _setScorValue(cp, m->instVarId, &m->value);
  1313. break;
  1314. default:
  1315. assert(0);
  1316. }
  1317. }
  1318. // This is the main UI<-Engine msg handler/dispatch function
  1319. void kcApp::_handleUiMsg( const cmDspUiHdr_t* m )
  1320. {
  1321. switch( m->selId )
  1322. {
  1323. case kPrintDuiId:
  1324. cmDsvPrint(&m->value,NULL,&_ctx->rpt);
  1325. break;
  1326. case kNumberDuiId:
  1327. case kSliderDuiId:
  1328. _createSlider(m);
  1329. break;
  1330. case kTextDuiId:
  1331. _createText(m);
  1332. break;
  1333. case kButtonDuiId:
  1334. _createButton(m);
  1335. break;
  1336. case kLabelDuiId:
  1337. _createLabel(m);
  1338. break;
  1339. case kCheckDuiId:
  1340. _createCheck(m);
  1341. break;
  1342. case kFnameDuiId:
  1343. _createFnameCtl(m);
  1344. break;
  1345. case kMsgListDuiId:
  1346. _createMlistCtl(m);
  1347. break;
  1348. case kMeterDuiId:
  1349. _createMeter(m);
  1350. break;
  1351. case kTimeLineDuiId:
  1352. _createTmln(m);
  1353. break;
  1354. case kScoreDuiId:
  1355. _createScor(m);
  1356. break;
  1357. case kValueDuiId:
  1358. _onRecvValue(m);
  1359. break;
  1360. case kColumnDuiId:
  1361. _newColumn(m);
  1362. break;
  1363. case kHBorderDuiId:
  1364. _horzBordFl = true;
  1365. break;
  1366. case kPageDuiId:
  1367. _createPage(cmDsvStrcz(&m->value));
  1368. break;
  1369. case kAudioSysCfgDuiId:
  1370. _insertAudioSysCfgLabel(m->instId,cmDsvStrcz(&m->value));
  1371. break;
  1372. case kDeviceDuiId:
  1373. _insertDeviceLabel(m->instId,m->flags,cmDsvStrcz(&m->value));
  1374. break;
  1375. case kProgramDuiId:
  1376. _insertProgramLabel(m->instId,cmDsvStrcz(&m->value));
  1377. break;
  1378. // the below codes are used to notify the application
  1379. // of changes in state of the audio DSP system
  1380. case kSubSysCntDuiId:
  1381. _insertSubSysCnt(cmDsvUInt(&m->value));
  1382. break;
  1383. case kSetAudioCfgDuiId:
  1384. _setMenuButton(_as_btn,cmDsvUInt(&m->value),"Audio System Cfg");
  1385. break;
  1386. case kSetAudioDevDuiId:
  1387. _setDeviceMenuButton( m->asSubIdx, m->flags, cmDsvUInt(&m->value) );
  1388. break;
  1389. case kSetSampleRateDuiId:
  1390. _setSampleRateBtn(cmDsvUInt(&m->value));
  1391. break;
  1392. case kSetPgmDuiId:
  1393. _setMenuButton(_pgm_btn,cmDsvUInt(&m->value),"Program?");
  1394. _clearCtlList(false);
  1395. break;
  1396. case kEnableDuiId:
  1397. _ena_chk->value(m->flags);
  1398. break;
  1399. }
  1400. }
  1401. // Check for and forward any messages sent to the UI
  1402. // that are waiting in the audio DSP msg queue.
  1403. void kcApp::_getEngMsg()
  1404. {
  1405. if( cmAdIfIsValid(_aiH) )
  1406. {
  1407. unsigned i;
  1408. for(i=0; i<10; ++i)
  1409. {
  1410. cmAiRC_t aiRC;
  1411. // cmAdIfDispatchMsgToHost() results in calls to
  1412. // the _s_handleXXX() message handlers
  1413. if((aiRC = cmAdIfDispatchMsgToHost(_aiH)) != kOkAiRC)
  1414. {
  1415. if( aiRC == kNoMsgAiRC )
  1416. break;
  1417. cmErrMsg(&_ctx->err,kEngFailKmRC,"Audio DSP dispatch message request failed.");
  1418. break;
  1419. }
  1420. }
  1421. }
  1422. }
  1423. kcApp* kcApp::_getApp( Fl_Widget* w )
  1424. {
  1425. // walk up the widget tree until the top widget is found
  1426. Fl_Group* gp = w->parent();
  1427. while( gp->parent() != NULL )
  1428. gp=gp->parent();
  1429. // the user data for the top widget is a pointer kcApp()
  1430. return (kcApp*)gp->user_data();
  1431. }
  1432. void kcApp::_onCloseApp()
  1433. {
  1434. if( _tlCtl != NULL )
  1435. {
  1436. delete _tlCtl;
  1437. _tlCtl = NULL;
  1438. }
  1439. _stopTimerFl = true;
  1440. // When all windows are windows are closed then the app.
  1441. // will close - so hiding the application window
  1442. // causes the program to close.
  1443. //
  1444. // Note that simply returning from this callback will
  1445. // prevent the application from closing. Because the existence
  1446. // of the callback alone is enough to disable default
  1447. // event handling.
  1448. hide();
  1449. }
  1450. void kcApp::_testStub()
  1451. {
  1452. /*
  1453. cmAudioFileTest(
  1454. // "/Users/kevin/media/audio/20100819-Kreisberg/fragments/Bass End_21a.wav",
  1455. "/Users/kevin/media/audio/McGill-1/1 Audio Track.aiff",
  1456. "/Users/kevin/src/octave/cm_audio_file_test.m",_ctx->err.rpt );
  1457. */
  1458. //cmSymTblTest(&_ctx);
  1459. //_kcTranslateFile("/Users/kevin/src/kc/src/data/Sec1_14.txt","/Users/kevin/src/kc/src/data/Sec1_14_out.txt",&_ctx);
  1460. //_kcTranslateFile("/Users/kevin/src/kc/src/data/Mix_17-20.txt","/Users/kevin/src/kc/src/data/Mix_17-20_out.txt",&_ctx);
  1461. /*
  1462. ctl_t* cp = _ctlList;
  1463. for(; cp!=NULL; cp=cp->linkPtr)
  1464. printf("%i %i %i\n", cp->instId,cp->asSubIdx,cp->mstrFl );
  1465. */
  1466. //_printStatusCounts();
  1467. //cmProcTestNoInit(&_ctx);
  1468. _tlCtl->testStub();
  1469. }
  1470. void kcApp::_printPgm()
  1471. {
  1472. const char* pathStr = cmFsUserDir(); // make the default dir the user's home dir
  1473. const char patStr[] = ""; //"Text Files (*.txt)\tAudio Files (*.{wav,aif,aiff})"; // All Files (*.*) is append to this automatically
  1474. const char titleStr[] = "JSON output file name";
  1475. Fl_File_Chooser fc = Fl_File_Chooser(pathStr,patStr,Fl_File_Chooser::CREATE,titleStr);
  1476. fc.preview(0); // default the previous option to 'off'.
  1477. fc.show(); // show the chooser
  1478. // make the chooser modal
  1479. while( fc.shown() )
  1480. Fl::wait();
  1481. if( fc.count() > 0)
  1482. cmAdIfPrintPgm(_aiH, cmInvalidIdx, fc.value(0) );
  1483. }
  1484. void kcApp::_s_callback(Fl_Widget* wp, void* data)
  1485. { ((kcApp*)data)->_callback(NULL); }
  1486. // this callback is called when the window is closing
  1487. void kcApp::_callback(void* data)
  1488. {
  1489. if( Fl::event() == FL_CLOSE )
  1490. {
  1491. _onCloseApp();
  1492. }
  1493. }
  1494. void kcApp::_s_status_timeout_cb(void* userPtr)
  1495. {
  1496. if( ((kcApp*)userPtr)->_status_timeout_cb() )
  1497. Fl::repeat_timeout(TIMER_PERIOD,_s_status_timeout_cb,userPtr);
  1498. }
  1499. bool kcApp::_status_timeout_cb()
  1500. {
  1501. if( cmTsMp1cIsValid(_printqH) )
  1502. _checkPrintQueue();
  1503. if( !_stopTimerFl )
  1504. {
  1505. _getEngMsg();
  1506. if( _tlCtl != NULL )
  1507. _tlCtl->onIdle();
  1508. }
  1509. if( _ssUpdateFl )
  1510. {
  1511. ++_ssPhase;
  1512. if( _ssPhase >= kSsPhaseMax )
  1513. {
  1514. _clearStatusIndicators();
  1515. _ssPhase = 0;
  1516. }
  1517. }
  1518. if( _stopTimerFl==false && cmAdIfIsValid(_aiH) )
  1519. cmAdIfDispatchMsgToHost(_aiH);
  1520. //if( !_stopTimerFl )
  1521. // _getEngStatus();
  1522. return _stopTimerFl==false || cmTsMp1cIsValid(_printqH);
  1523. }
  1524. void kcApp::_s_menu_cb(Fl_Widget *w, void *data)
  1525. {
  1526. const Fl_Menu_Item* mip;
  1527. kcApp* p;
  1528. if((p=_getApp(w)) == NULL )
  1529. return;
  1530. if((mip = p->_menu->mvalue()) == NULL )
  1531. return;
  1532. unsigned id = (long int)mip->user_data();
  1533. switch(id)
  1534. {
  1535. case kAboutMenuId:
  1536. fl_message("%s Compiled:%s %s",PACKAGE_STRING,__DATE__,__TIME__);
  1537. break;
  1538. case kQuitMenuId:
  1539. p->_onCloseApp();
  1540. break;
  1541. }
  1542. }
  1543. void kcApp::_s_tab_cb(Fl_Widget* w, void* data)
  1544. { ((kcApp*)data)->_tab_cb(w); }
  1545. void kcApp::_tab_cb(Fl_Widget*)
  1546. {
  1547. Fl_Widget* w = _tabs->value();
  1548. _ssUpdateFl = w == (Fl_Widget*)_mstr_grp;
  1549. _ssPhase = kSsPhaseMax;
  1550. if( cmAdIfIsValid(_aiH) )
  1551. {
  1552. if( cmAdIfEnableStatusNotify(_aiH, _ssUpdateFl ) != kOkAiRC )
  1553. cmErrMsg(&_ctx->err,kEngFailKmRC,"A request to enable/disable status notification failed.");
  1554. }
  1555. }
  1556. void kcApp::_s_btn_cb(Fl_Widget* w, long data)
  1557. {
  1558. _getApp(w)->_btn_cb(w,data);
  1559. }
  1560. void kcApp::_btn_cb(Fl_Widget* w, long data)
  1561. {
  1562. unsigned arg = w->argument();
  1563. switch( arg )
  1564. {
  1565. case kAudDevRptBtnId:
  1566. cmAdIfDeviceReport(_aiH);
  1567. break;
  1568. case kEnableBtnId:
  1569. cmAdIfEnableAudio(_aiH,static_cast<Fl_Check_Button*>(w)->value()!=0);
  1570. break;
  1571. case kAudioSysCfgBtnId:
  1572. cmAdIfSetAudioSysCfg(_aiH,static_cast<Fl_Menu_Button*>(w)->mvalue()->argument());
  1573. break;
  1574. case kInAudDevBtnId:
  1575. cmAdIfSetAudioDevice(_aiH,_getCurAudioSubSysIdx(),true,static_cast<Fl_Menu_Button*>(w)->mvalue()->argument());
  1576. break;
  1577. case kOutAudDevBtnId:
  1578. cmAdIfSetAudioDevice(_aiH,_getCurAudioSubSysIdx(),false,static_cast<Fl_Menu_Button*>(w)->mvalue()->argument());
  1579. break;
  1580. case kPgmBtnId:
  1581. cmAdIfLoadProgram(_aiH,_getCurAudioSubSysIdx(),static_cast<Fl_Menu_Button*>(w)->mvalue()->argument());
  1582. break;
  1583. case kSubSystemIdxBtnId:
  1584. // TODO: change device and sample rate menu's to reflect the device and srate assigned to this asSubIdx.
  1585. break;
  1586. case kSrateBtnId:
  1587. cmAdIfSetSampleRate(_aiH,_getCurAudioSubSysIdx(),static_cast<Fl_Menu_Button*>(w)->mvalue()->argument());
  1588. break;
  1589. case kTestBtnId:
  1590. _testStub();
  1591. break;
  1592. case kPrintPgmBtnId:
  1593. _printPgm();
  1594. break;
  1595. default:
  1596. { assert(0); }
  1597. }
  1598. }
  1599. void kcApp::_s_ctl_cb(Fl_Widget* w, void* data)
  1600. {
  1601. ctl_t* cp = ((ctl_t*)data);
  1602. cp->thisPtr->_ctl_cb(cp);
  1603. }
  1604. void kcApp::_ctl_cb(ctl_t* cp)
  1605. {
  1606. cmDspValue_t value = cmDspNullValue;
  1607. unsigned instVarId = cmInvalidId;
  1608. switch( cp->typeId )
  1609. {
  1610. case kNumbTypeId:
  1611. case kSldrTypeId:
  1612. instVarId = cp->u.sldr.varIdArray[ kSldrValArgIdx ];
  1613. cmDsvSetDouble(&value,cp->u.sldr.val->value());
  1614. break;
  1615. case kTextTypeId:
  1616. instVarId = cp->u.text.varIdArray[ kTextValArgIdx ];
  1617. cmDsvSetStrz(&value,(cmChar_t*)cp->u.text.text->value());
  1618. break;
  1619. case kButnTypeId:
  1620. instVarId = cp->u.butn.varIdArray[ kButnValArgIdx ];
  1621. cmDsvSetDouble(&value,cp->u.butn.val);
  1622. break;
  1623. case kChckTypeId:
  1624. {
  1625. bool fl = cp->u.chck.chck->value();
  1626. instVarId = cp->u.chck.varIdArray[ kChckValArgIdx ];
  1627. cmDsvSetDouble(&value, fl ? 1.0 : 0.0 );
  1628. }
  1629. break;
  1630. case kFnamTypeId:
  1631. instVarId = cp->u.fnam.varIdArray[ kFnamValArgIdx ];
  1632. cmDsvSetStrz( &value, (cmChar_t*)cp->u.fnam.fnam->filename());
  1633. break;
  1634. case kMlstTypeId:
  1635. instVarId = cp->u.mlst.varIdArray[ kMlstSelArgIdx ];
  1636. // add one to the selected index to account for skipping title row
  1637. if( cp->u.mlst.mbtn==NULL)
  1638. {
  1639. unsigned idx = cp->u.mlst.mlst->value();
  1640. //printf("list:%i\n",idx);
  1641. cmDsvSetUInt( &value, idx);
  1642. }
  1643. else
  1644. {
  1645. unsigned idx = cp->u.mlst.mbtn->value();
  1646. //printf("mbtn:%i\n",idx);
  1647. cmDsvSetUInt( &value, idx + 1);
  1648. cp->u.mlst.mbtn->label( cp->u.mlst.mbtn->text(idx) );
  1649. }
  1650. break;
  1651. case kTmlnTypeId:
  1652. {
  1653. instVarId = cp->u.tmln.varIdArray[ kTmlnSelArgIdx ];
  1654. unsigned selMarkerId = cp->u.tmln.tlctl->timeLineSelectedMarkerId();
  1655. cmDsvSetUInt(&value, selMarkerId );
  1656. }
  1657. break;
  1658. case kScorTypeId:
  1659. {
  1660. instVarId = cp->u.scor.varIdArray[ kScorSelArgIdx ];
  1661. unsigned selEleIdx = cp->u.scor.tlctl->scoreSelectedEleIndex();
  1662. cmDsvSetUInt(&value, selEleIdx );
  1663. }
  1664. break;
  1665. default:
  1666. {assert(0);}
  1667. }
  1668. if( cmAdIfSendMsgToAudioDSP(
  1669. _aiH,
  1670. cp->asSubIdx,
  1671. cp->mstrFl ? kUiMstrSelAsId : kUiSelAsId,
  1672. kValueDuiId,
  1673. 0,
  1674. cp->instId,
  1675. instVarId,
  1676. &value) != kOkAiRC)
  1677. {
  1678. cmErrMsg(&_ctx->err,kEngFailKmRC,"An attempt to send a UI message to the audio DSP interface failed.");
  1679. }
  1680. }
  1681. void kcApp::vprint(const char* fmt, va_list vl )
  1682. {
  1683. int bufCharCnt = 511;
  1684. char buf[bufCharCnt+1];
  1685. int n = vsnprintf(buf,bufCharCnt,fmt,vl);
  1686. if( n > 0 )
  1687. {
  1688. // if the print queue exists (it might not during startup or shutdown) ...
  1689. if( cmTsMp1cIsValid(_printqH) )
  1690. {
  1691. // ... enqueue the text to print
  1692. if( cmTsMp1cEnqueueMsg(_printqH,buf,n+1) != kOkThRC && _printFl==0 )
  1693. {
  1694. // use _printFl to guard against recursion which would eventually overflow the stack.
  1695. ++_printFl;
  1696. cmErrMsg(&_ctx->err,kQueueFailKmRC,"Print enqueue failed on msg:%s.",buf);
  1697. --_printFl;
  1698. }
  1699. }
  1700. else
  1701. _print(buf); // ... otherwise just send the text directly to the output console
  1702. }
  1703. }
  1704. void kcApp::print( const char* fmt, ... )
  1705. {
  1706. va_list vl;
  1707. va_start(vl,fmt);
  1708. vprint(fmt,vl);
  1709. va_end(vl);
  1710. }
  1711. void kcApp::_s_print( void* userPtr, const char* text )
  1712. { ((kcApp*)userPtr)->print(text); }
  1713. cmRC_t kcApp::_s_print_queue_cb(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr )
  1714. {
  1715. kcApp* ap = (kcApp*)userCbPtr;
  1716. ap->_print((const char*)msgDataPtr);
  1717. return cmOkRC;
  1718. }
  1719. void kcApp::_checkPrintQueue()
  1720. {
  1721. while( cmTsMp1cMsgWaiting(_printqH) )
  1722. if( cmTsMp1cDequeueMsg(_printqH, NULL, 0) != kOkThRC && _printFl==0 )
  1723. {
  1724. ++_printFl;
  1725. cmErrMsg(&_ctx->err,kPrintQueFailKmRC,"Print dequeue failed.");
  1726. --_printFl;
  1727. }
  1728. }
  1729. void kcApp::_print( const char* text )
  1730. {
  1731. if( _con != NULL )
  1732. _con->insert(text);
  1733. #ifndef NDEBUG
  1734. fputs(text,stdout);
  1735. #endif
  1736. }