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.

367 lines
8.5KB

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