Audio plugin host https://kx.studio/carla
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.

BankView.cpp 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. BankView.cpp - View Of Bank Fields
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include "BankView.h"
  11. #include "../Misc/Util.h"
  12. #include <FL/Fl.H>
  13. #include <FL/Fl_Check_Button.H>
  14. #include <FL/fl_ask.H>
  15. #include <rtosc/rtosc.h>
  16. #include <cstdio>
  17. #include <cstring>
  18. #include <cassert>
  19. using namespace zyncarla;
  20. BankList::BankList(int x,int y, int w, int h, const char *label)
  21. :Fl_Osc_Choice(x,y,w,h,label)
  22. {}
  23. void BankList::init(std::string path)
  24. {
  25. ext = path;
  26. oscRegister("bank/bank_select");
  27. oscRegister(path.c_str());
  28. oscWrite("bank/banks", "");
  29. }
  30. void BankList::OSC_raw(const char *msg)
  31. {
  32. if(!strcmp(msg, "/bank/bank_select") && !strcmp(rtosc_argument_string(msg),"iss")) {
  33. const int pos = rtosc_argument(msg, 0).i;
  34. const char *path = rtosc_argument(msg, 1).s;
  35. value(0);
  36. if(pos == 0)
  37. this->clear();
  38. if(pos <= this->size()-2) {
  39. return;
  40. }
  41. this->add(path);
  42. }
  43. if(!strcmp(msg, "/bank/bank_select")&& !strcmp(rtosc_argument_string(msg),"i")) {
  44. int val = rtosc_argument(msg, 0).i;
  45. if(value() != val) {
  46. value(val);
  47. for(int i=0; i<160; ++i)
  48. osc->write("/bank/slot"+to_s(i), "");
  49. }
  50. }
  51. }
  52. BankSlot::BankSlot(int x,int y, int w, int h, const char *label)
  53. :Fl_Button(x,y,w,h,label), nslot(-1)
  54. {
  55. memset(labelstr, 0, sizeof(labelstr));
  56. box(FL_THIN_UP_BOX);
  57. labelfont(0);
  58. labelsize(13);
  59. align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
  60. }
  61. int BankSlot::handle(int event)
  62. {
  63. int what = 0;
  64. if (Fl::event_inside(this))
  65. {
  66. what=0;
  67. if ((event==FL_RELEASE)&&(Fl::event_button()==1))
  68. what=1;
  69. if ((event==FL_RELEASE)&&(Fl::event_button()==3))
  70. what=2;
  71. }
  72. int tmp=Fl_Button::handle(event);
  73. if (what && Fl::event_inside(this))
  74. bv->react(what, nslot);
  75. return tmp;
  76. }
  77. void BankSlot::init(int nslot_, BankView *bv_)
  78. {
  79. nslot = nslot_;
  80. bv = bv_;
  81. snprintf(labelstr, 127, "%d.", nslot_);
  82. label(labelstr);
  83. }
  84. void BankSlot::update(const char *name__, const char *fname__)
  85. {
  86. name_ = name__;
  87. filename_ = fname__;
  88. snprintf(labelstr, 127, "%d. %s", nslot, name_.c_str());
  89. label(labelstr);
  90. if(name_.empty())
  91. label("");
  92. color(empty() ? 46 : 51);
  93. #ifdef NTK_GUI
  94. redraw();
  95. #endif
  96. }
  97. bool BankSlot::empty(void) const
  98. {
  99. return filename_.empty();
  100. }
  101. const char *BankSlot::name(void) const
  102. {
  103. return name_.c_str();
  104. }
  105. const char *BankSlot::filename(void) const
  106. {
  107. return filename_.c_str();
  108. }
  109. /*
  110. void BankSlot::init(int nslot_, int *what_, int *whatslot_,void (BankProcess_:: *fnc_)(void),BankProcess_ *bp_,Bank *bank_,int *nselected_) {
  111. nslot=nslot_;
  112. what=what_;
  113. whatslot=whatslot_;
  114. fnc=fnc_;
  115. bp=bp_;
  116. //bank=bank_;
  117. nselected=nselected_;
  118. box(FL_THIN_UP_BOX);
  119. labelfont(0);
  120. labelsize(13);
  121. align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
  122. highlight=0;
  123. //refresh();
  124. }
  125. */
  126. /*
  127. void BankSlot::refresh() {
  128. if (bank->emptyslot(nslot))
  129. color(46);
  130. else if (bank->isPADsynth_used(nslot))
  131. color(26);
  132. else
  133. color(51);
  134. if (*nselected==nslot)
  135. color(6);
  136. copy_label(bank->getnamenumbered(nslot).c_str());
  137. }
  138. */
  139. static int modeCb(const char *label)
  140. {
  141. if(!strcmp("Read", label))
  142. return 1;
  143. else if(!strcmp("Write", label))
  144. return 2;
  145. else if(!strcmp("Clear", label))
  146. return 3;
  147. else if(!strcmp("Swap", label))
  148. return 4;
  149. return -1;
  150. }
  151. static void modeButtonCb(Fl_Widget *w, void *v)
  152. {
  153. BankViewControls *bvc = (BankViewControls*)v;
  154. bvc->mode(modeCb(w->label()));
  155. }
  156. BankViewControls::BankViewControls(int x, int y, int w, int h, const char *label)
  157. :Fl_Group(x,y,w,h,label)
  158. {
  159. //Margin
  160. const int m = 10;
  161. //Width per elm
  162. const float W = w/4;
  163. read = new Fl_Check_Button(x+m+0*W, y+m, W-2*m, h-2*m, "Read");
  164. write = new Fl_Check_Button(x+m+1*W, y+m, W-2*m, h-2*m, "Write");
  165. clear = new Fl_Check_Button(x+m+2*W, y+m, W-2*m, h-2*m, "Clear");
  166. swap = new Fl_Check_Button(x+m+3*W, y+m, W-2*m, h-2*m, "Swap");
  167. read->box(FL_BORDER_BOX);
  168. write->box(FL_BORDER_BOX);
  169. clear->box(FL_BORDER_BOX);
  170. swap->box(FL_BORDER_BOX);
  171. read->callback(modeButtonCb, this);
  172. write->callback(modeButtonCb, this);
  173. clear->callback(modeButtonCb, this);
  174. swap->callback(modeButtonCb, this);
  175. mode(1);
  176. }
  177. int BankViewControls::mode(void) const
  178. {
  179. return mode_;
  180. }
  181. void BankViewControls::mode(int m)
  182. {
  183. mode_ = m;
  184. int M = m-1;
  185. assert(0 <= M && M <= 3);
  186. Fl_Button *buttons[4]{read, write, clear, swap};
  187. for(int i=0; i<4; ++i)
  188. buttons[i]->value(i==M);
  189. }
  190. BankView::BankView(int x,int y, int w, int h, const char *label)
  191. :Fl_Group(x,y,w,h,label), Fl_Osc_Widget(),
  192. bvc(NULL), slots{0}, nselected(-1), npart(0), cbwig_(0)
  193. {}
  194. BankView::~BankView(void)
  195. {
  196. if(osc) {
  197. osc->removeLink("/bankview", this);
  198. osc->removeLink("/bank/search_results", this);
  199. }
  200. }
  201. void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_)
  202. {
  203. assert(osc_);
  204. osc = osc_;
  205. bvc = bvc_;
  206. npart = npart_;
  207. osc->createLink("/bankview", this);
  208. osc->createLink("/bank/search_results", this);
  209. //Element Size
  210. const float width = w()/5.0;
  211. const float height = h()/32.0;
  212. //Offsets
  213. const int X = x();
  214. const int Y = y();
  215. begin();
  216. //Place All Slots
  217. for(int i=0; i<5; ++i)
  218. for(int j=0; j<32; ++j)
  219. slots[i*32 + j] =
  220. new BankSlot(X + i*width, Y + j*height, width, height);
  221. end();
  222. //Initialize callbacks
  223. for(int i=0; i<160; ++i)
  224. slots[i]->init(i, this);
  225. //Create Slot Listeners
  226. for(int i=0; i<160; ++i)
  227. osc->createLink("/bank/slot"+to_s(i), this);
  228. //Request Values
  229. for(int i=0; i<160; ++i)
  230. osc->write("/bank/slot"+to_s(i), "");
  231. }
  232. /*
  233. * React to user input.
  234. * This consists of the events:
  235. * - Rename Slot (right click)
  236. * - Read From Slot
  237. * - Write To Slot
  238. * - Swap Slot First Selection
  239. * - Swap Slot Second Selction
  240. *
  241. * TODO restore autoclose functionality
  242. */
  243. void BankView::react(int event, int nslot)
  244. {
  245. BankSlot &slot = *slots[nslot];
  246. const bool isempty = slot.empty();
  247. const int mode = bvc->mode();
  248. //Rename slot
  249. if (event==2 && !isempty && mode!=4) {
  250. if(const char *name=fl_input("Slot (instrument) name:", slot.name())) {
  251. osc->write("/bank/rename_slot", "is", nslot, name);
  252. osc->write("/bank/slot"+to_s(nslot), "");
  253. }
  254. }
  255. //Reads from slot
  256. if ((event==1)&&(mode==1) && !isempty){
  257. printf("Loading a part #%d with file '%s'\n", nslot, slot.filename());
  258. osc->write("/load-part", "iss", *npart, slot.filename(),
  259. slot.name());
  260. osc->writeValue("/part"+to_s(*npart)+"/Pname", slot.name());
  261. if(cbwig_)
  262. cbwig_->do_callback();
  263. }
  264. //save(write) to slot
  265. if(event==1 && mode==2){
  266. if(isempty ||
  267. fl_choice("Overwrite the slot no. %d ?","No","Yes",NULL,nslot+1)) {
  268. osc->write("/bank/save_to_slot", "ii", *npart, nslot);
  269. osc->write("/bank/slot"+to_s(nslot), "");
  270. }
  271. bvc->mode(1);
  272. }
  273. //Clears the slot
  274. if(event==1 && mode==3) {
  275. if (!isempty &&
  276. fl_choice("Clear the slot no. %d ?","No","Yes",NULL, nslot+1)) {
  277. osc->write("/bank/clear_slot", "i", nslot);
  278. osc->write("/bank/slot"+to_s(nslot), "");
  279. }
  280. bvc->mode(1);
  281. }
  282. //Swap
  283. if(mode==4) {
  284. if(event==1 && nselected>=0){
  285. osc->write("/bank/swap_slots", "ii", nselected, nslot);
  286. osc->write("/bank/slot"+to_s(nslot), "");
  287. osc->write("/bank/slot"+to_s(nselected), "");
  288. nselected=-1;
  289. } else if(nselected<0 || event==2) {
  290. nselected=nslot;
  291. };
  292. };
  293. }
  294. void BankView::OSC_raw(const char *msg)
  295. {
  296. if(!strcmp(msg, "/bank/search_results")) {
  297. const char *ptr = rtosc_argument_string(msg);
  298. int slot = 0;
  299. while (ptr[0] == 's' && ptr[1] == 's') {
  300. const char *bank = rtosc_argument(msg, 2*slot).s;
  301. const char *fname = rtosc_argument(msg, 2*slot + 1).s;
  302. /* store search results directly into slot */
  303. slots[slot]->update(bank, fname);
  304. if (++slot == 160)
  305. break;
  306. ptr += 2;
  307. }
  308. while (slot < 160)
  309. slots[slot++]->update("", "");
  310. } else if(!strcmp(rtosc_argument_string(msg), "iss")) {
  311. int nslot = rtosc_argument(msg,0).i;
  312. const char *name = rtosc_argument(msg,1).s;
  313. const char *fname = rtosc_argument(msg,2).s;
  314. if(0 <= nslot && nslot < 160)
  315. slots[nslot]->update(name, fname);
  316. } else if(!strcmp(rtosc_argument_string(msg), "ss")) {
  317. while(*msg && !isdigit(*msg)) msg++;
  318. int nslot = atoi(msg);
  319. const char *name = rtosc_argument(msg,0).s;
  320. const char *fname = rtosc_argument(msg,1).s;
  321. if(0 <= nslot && nslot < 160)
  322. slots[nslot]->update(name, fname);
  323. }
  324. }
  325. void BankView::cbwig(Fl_Widget *w)
  326. {
  327. cbwig_ = w;
  328. }
  329. void BankView::refresh(void)
  330. {
  331. assert(osc);
  332. //Odd case during initialization
  333. if(!osc)
  334. return;
  335. for(int i=0; i<160; ++i)
  336. osc->write("/bank/slot"+to_s(i), "");
  337. }