zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

BankView.cpp (9666B)


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