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.

362 lines
8.3KB

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