| 
							- #include <rtosc/automations.h>
 - #include <cmath>
 - 
 - using namespace rtosc;
 - 
 - AutomationMgr::AutomationMgr(int slots, int per_slot, int control_points)
 -     :nslots(slots), per_slot(per_slot), active_slot(0), learn_queue_len(0), p(NULL), damaged(0)
 - {
 -     this->slots = new AutomationSlot[slots];
 -     memset(this->slots, 0, sizeof(AutomationSlot)*slots);
 -     for(int i=0; i<slots; ++i) {
 -         auto &s = this->slots[i];
 -         sprintf(s.name, "Slot %d", i);
 -         s.midi_cc  = -1;
 -         s.learning = -1;
 - 
 -         s.automations = new Automation[per_slot];
 -         memset(s.automations, 0, sizeof(Automation)*per_slot);
 -         for(int j=0; j<per_slot; ++j) {
 -             s.automations[j].map.control_points = new float[control_points];
 -             s.automations[j].map.npoints = control_points;
 -             s.automations[j].map.gain   = 100.0;
 -             s.automations[j].map.offset = 0.0;
 -         }
 -     }
 - 
 - }
 - AutomationMgr::~AutomationMgr(void)
 - {
 - }
 - 
 - void AutomationMgr::createBinding(int slot, const char *path, bool start_midi_learn)
 - {
 -     assert(p);
 -     const Port *port = p->apropos(path);
 -     if(!port) {
 -         fprintf(stderr, "[Zyn:Error] port '%s' does not exist\n", path);
 -         return;
 -     }
 -     auto meta = port->meta();
 -     if(!(meta.find("min") && meta.find("max"))) {
 -         if(!strstr(port->name, ":T")) {
 -             fprintf(stderr, "No bounds for '%s' known\n", path);
 -             return;
 -         }
 -     }
 -     if(meta.find("internal") || meta.find("no learn")) {
 -         fprintf(stderr, "[Warning] port '%s' is unlearnable\n", path);
 -         return;
 -     }
 -     int ind = -1;
 -     for(int i=0; i<per_slot; ++i) {
 -         if(slots[slot].automations[i].used == false) {
 -             ind = i;
 -             break;
 -         }
 -     }
 - 
 -     if(ind == -1)
 -         return;
 - 
 -     slots[slot].used = true;
 - 
 -     auto &au = slots[slot].automations[ind];
 - 
 -     au.used   = true;
 -     au.active = true;
 -     au.param_type = 'i';
 -     if(strstr(port->name, ":f"))
 -         au.param_type = 'f';
 -     else if(strstr(port->name, ":T"))
 -         au.param_type = 'T';
 -     if(au.param_type == 'T') {
 -         au.param_min = 0.0;
 -         au.param_max = 1.0;
 -     } else {
 -         au.param_min = atof(meta["min"]);
 -         au.param_max = atof(meta["max"]);
 -     }
 -     strncpy(au.param_path, path, sizeof(au.param_path));
 - 
 -     au.map.gain   = 100.0;
 -     au.map.offset = 0;
 -     updateMapping(slot, ind);
 - 
 -     if(start_midi_learn && slots[slot].learning == -1 && slots[slot].midi_cc == -1)
 -         slots[slot].learning = ++learn_queue_len;
 - 
 -     damaged = true;
 - 
 - };
 - 
 - void AutomationMgr::updateMapping(int slot_id, int sub)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
 -         return;
 - 
 - 
 -     auto &au = slots[slot_id].automations[sub];
 - 
 -     float mn = au.param_min;
 -     float mx = au.param_max;
 -     float center = (mn+mx)*(0.5 + au.map.offset/100.0);
 -     float range  = (mx-mn)*au.map.gain/100.0;
 - 
 -     au.map.upoints = 2;
 -     au.map.control_points[0] = 0;
 -     au.map.control_points[1] = center-range/2.0;
 -     au.map.control_points[2] = 1;
 -     au.map.control_points[3] = center+range/2.0;
 - }
 - 
 - void AutomationMgr::setSlot(int slot_id, float value)
 - {
 -     if(slot_id >= nslots || slot_id < 0)
 -         return;
 -     for(int i=0; i<per_slot; ++i)
 -         setSlotSub(slot_id, i, value);
 - 
 -     slots[slot_id].current_state = value;
 - }
 - 
 - void AutomationMgr::setSlotSub(int slot_id, int par, float value)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || par >= per_slot || par < 0)
 -         return;
 -     auto &au = slots[slot_id].automations[par];
 -     if(au.used == false)
 -         return;
 -     const char *path = au.param_path;
 -     float mn = au.param_min;
 -     float mx = au.param_max;
 - 
 -     float a  = au.map.control_points[1];
 -     float b  = au.map.control_points[3];
 - 
 -     char type = au.param_type;
 - 
 -     char msg[256] = {0};
 -     if(type == 'i') {
 -         float v = value*(b-a) + a;
 -         if(v > mx)
 -             v = mx;
 -         else if(v < mn)
 -             v = mn;
 - 
 -         rtosc_message(msg, 256, path, "i", (int)roundf(v));
 -     } else if(type == 'f') {
 -         float v = value*(b-a) + a;
 -         if(v > mx)
 -             v = mx;
 -         else if(v < mn)
 -             v = mn;
 - 
 -         rtosc_message(msg, 256, path, "f", v);
 -     } else if(type == 'T' || type == 'F') {
 -         float v = value*(b-a) + a;
 -         if(v > 0.5)
 -             v = 1.0;
 -         else
 -             v = 0.0;
 - 
 -         rtosc_message(msg, 256, path, v == 1.0 ? "T" : "F");
 -     } else
 -         return;
 - 
 -     if(backend)
 -         backend(msg);
 - }
 - 
 - float AutomationMgr::getSlot(int slot_id)
 - {
 -     if(slot_id >= nslots || slot_id < 0)
 -         return 0.0;
 -     return slots[slot_id].current_state;
 - }
 - 
 - 
 - void AutomationMgr::clearSlot(int slot_id)
 - {
 -     if(slot_id >= nslots || slot_id < 0)
 -         return;
 -     auto &s = slots[slot_id];
 -     s.active = false;
 -     s.used   = false;
 -     if(s.learning)
 -         learn_queue_len--;
 -     for(int i=0; i<nslots; ++i)
 -         if(slots[i].learning > s.learning)
 -             slots[i].learning--;
 -     s.learning = -1;
 -     s.midi_cc  = -1;
 -     s.current_state = 0;
 -     memset(s.name, 0, sizeof(s.name));
 -     sprintf(s.name, "Slot %d", slot_id);
 -     for(int i=0; i<per_slot; ++i)
 -         clearSlotSub(slot_id, i);
 -     damaged = true;
 - }
 - 
 - void AutomationMgr::clearSlotSub(int slot_id, int sub)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
 -         return;
 -     auto &a = slots[slot_id].automations[sub];
 -     a.used    = false;
 -     a.active  = false;
 -     a.relative = false;
 -     a.param_base_value = false;
 -     memset(a.param_path, 0, sizeof(a.param_path));
 -     a.param_type = 0;
 -     a.param_min  = 0;
 -     a.param_max  = 0;
 -     a.param_step = 0;
 -     a.map.gain   = 100;
 -     a.map.offset = 0;
 - 
 -     damaged = true;
 - }
 - 
 - void  AutomationMgr::setSlotSubGain(int slot_id, int sub, float f)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
 -         return;
 -     auto &m = slots[slot_id].automations[sub].map;
 -     m.gain = f;
 - }
 - float AutomationMgr::getSlotSubGain(int slot_id, int sub)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
 -         return 0.0;
 -     auto &m = slots[slot_id].automations[sub].map;
 -     return m.gain;
 - }
 - void  AutomationMgr::setSlotSubOffset(int slot_id, int sub, float f)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
 -         return;
 -     auto &m = slots[slot_id].automations[sub].map;
 -     m.offset = f;
 - }
 - float AutomationMgr::getSlotSubOffset(int slot_id, int sub)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
 -         return 0.0;
 -     auto &m = slots[slot_id].automations[sub].map;
 -     return m.offset;
 - }
 - 
 - void AutomationMgr::setName(int slot_id, const char *msg)
 - {
 -     if(slot_id >= nslots || slot_id < 0)
 -         return;
 -     strncpy(slots[slot_id].name, msg, sizeof(slots[slot_id].name));
 -     damaged = 1;
 - }
 - const char *AutomationMgr::getName(int slot_id)
 - {
 -     if(slot_id >= nslots || slot_id < 0)
 -         return "";
 -     return slots[slot_id].name;
 - }
 - bool AutomationMgr::handleMidi(int channel, int cc, int val)
 - {
 -     int ccid = channel*128 + cc;
 - 
 -     bool bound_cc = false;
 -     for(int i=0; i<nslots; ++i) {
 -         if(slots[i].midi_cc == ccid) {
 -             bound_cc = true;
 -             setSlot(i, val/127.0);
 -         }
 -     }
 - 
 -     if(bound_cc)
 -         return 1;
 - 
 -     //No bound CC, now to see if there's something to learn
 -     for(int i=0; i<nslots; ++i) {
 -         if(slots[i].learning == 1) {
 -             slots[i].learning = -1;
 -             slots[i].midi_cc = ccid;
 -             for(int j=0; j<nslots; ++j)
 -                 if(slots[j].learning > 1)
 -                     slots[j].learning -= 1;
 -             learn_queue_len--;
 -             setSlot(i, val/127.0);
 -             damaged = 1;
 -             break;
 -         }
 -     }
 -     return 0;
 - }
 - 
 - void AutomationMgr::set_ports(const struct Ports &p_) {
 -     p = &p_;
 - };
 - //
 - //        AutomationSlot *slots;
 - //        struct AutomationMgrImpl *impl;
 - //};
 - void AutomationMgr::set_instance(void *v)
 - {
 -     this->instance = v;
 - }
 - 
 - void AutomationMgr::simpleSlope(int slot_id, int par, float slope, float offset)
 - {
 -     if(slot_id >= nslots || slot_id < 0 || par >= per_slot || par < 0)
 -         return;
 -     auto &map = slots[slot_id].automations[par].map;
 -     map.upoints = 2;
 -     map.control_points[0] = 0;
 -     map.control_points[1] = -(slope/2)+offset;
 -     map.control_points[2] =  1;
 -     map.control_points[3] =  slope/2+offset;
 - 
 - }
 - 
 - int AutomationMgr::free_slot(void) const
 - {
 -     for(int i=0; i<nslots; ++i)
 -         if(!slots[i].used)
 -             return i;
 -     return -1;
 - }
 
 
  |