LMMS
Loading...
Searching...
No Matches
automations.cpp
Go to the documentation of this file.
1#include <rtosc/automations.h>
2#include <cmath>
3
4using namespace rtosc;
5
6AutomationMgr::AutomationMgr(int slots, int per_slot, int control_points)
8{
9 this->slots = new AutomationSlot[slots];
10 memset(this->slots, 0, sizeof(AutomationSlot)*slots);
11 for(int i=0; i<slots; ++i) {
12 auto &s = this->slots[i];
13 sprintf(s.name, "Slot %d", i);
14 s.midi_cc = -1;
15 s.learning = -1;
16
17 s.automations = new Automation[per_slot];
18 memset(s.automations, 0, sizeof(Automation)*per_slot);
19 for(int j=0; j<per_slot; ++j) {
20 s.automations[j].map.control_points = new float[control_points];
21 s.automations[j].map.npoints = control_points;
22 s.automations[j].map.gain = 100.0;
23 s.automations[j].map.offset = 0.0;
24 }
25 }
26
27}
31
32void AutomationMgr::createBinding(int slot, const char *path, bool start_midi_learn)
33{
34 assert(p);
35 const Port *port = p->apropos(path);
36 if(!port) {
37 fprintf(stderr, "[Zyn:Error] port '%s' does not exist\n", path);
38 return;
39 }
40 auto meta = port->meta();
41 if(!(meta.find("min") && meta.find("max"))) {
42 if(!strstr(port->name, ":T")) {
43 fprintf(stderr, "No bounds for '%s' known\n", path);
44 return;
45 }
46 }
47 if(meta.find("internal") || meta.find("no learn")) {
48 fprintf(stderr, "[Warning] port '%s' is unlearnable\n", path);
49 return;
50 }
51 int ind = -1;
52 for(int i=0; i<per_slot; ++i) {
53 if(slots[slot].automations[i].used == false) {
54 ind = i;
55 break;
56 }
57 }
58
59 if(ind == -1)
60 return;
61
62 slots[slot].used = true;
63
64 auto &au = slots[slot].automations[ind];
65
66 au.used = true;
67 au.active = true;
68 au.param_type = 'i';
69 if(strstr(port->name, ":f"))
70 au.param_type = 'f';
71 else if(strstr(port->name, ":T"))
72 au.param_type = 'T';
73 if(au.param_type == 'T') {
74 au.param_min = 0.0;
75 au.param_max = 1.0;
76 } else {
77 au.param_min = atof(meta["min"]);
78 au.param_max = atof(meta["max"]);
79 }
80 strncpy(au.param_path, path, sizeof(au.param_path));
81
82 au.map.gain = 100.0;
83 au.map.offset = 0;
84 updateMapping(slot, ind);
85
86 if(start_midi_learn && slots[slot].learning == -1 && slots[slot].midi_cc == -1)
87 slots[slot].learning = ++learn_queue_len;
88
89 damaged = true;
90
91};
92
93void AutomationMgr::updateMapping(int slot_id, int sub)
94{
95 if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
96 return;
97
98
99 auto &au = slots[slot_id].automations[sub];
100
101 float mn = au.param_min;
102 float mx = au.param_max;
103 float center = (mn+mx)*(0.5 + au.map.offset/100.0);
104 float range = (mx-mn)*au.map.gain/100.0;
105
106 au.map.upoints = 2;
107 au.map.control_points[0] = 0;
108 au.map.control_points[1] = center-range/2.0;
109 au.map.control_points[2] = 1;
110 au.map.control_points[3] = center+range/2.0;
111}
112
113void AutomationMgr::setSlot(int slot_id, float value)
114{
115 if(slot_id >= nslots || slot_id < 0)
116 return;
117 for(int i=0; i<per_slot; ++i)
118 setSlotSub(slot_id, i, value);
119
120 slots[slot_id].current_state = value;
121}
122
123void AutomationMgr::setSlotSub(int slot_id, int par, float value)
124{
125 if(slot_id >= nslots || slot_id < 0 || par >= per_slot || par < 0)
126 return;
127 auto &au = slots[slot_id].automations[par];
128 if(au.used == false)
129 return;
130 const char *path = au.param_path;
131 float mn = au.param_min;
132 float mx = au.param_max;
133
134 float a = au.map.control_points[1];
135 float b = au.map.control_points[3];
136
137 char type = au.param_type;
138
139 char msg[256] = {0};
140 if(type == 'i') {
141 float v = value*(b-a) + a;
142 if(v > mx)
143 v = mx;
144 else if(v < mn)
145 v = mn;
146
147 rtosc_message(msg, 256, path, "i", (int)roundf(v));
148 } else if(type == 'f') {
149 float v = value*(b-a) + a;
150 if(v > mx)
151 v = mx;
152 else if(v < mn)
153 v = mn;
154
155 rtosc_message(msg, 256, path, "f", v);
156 } else if(type == 'T' || type == 'F') {
157 float v = value*(b-a) + a;
158 if(v > 0.5)
159 v = 1.0;
160 else
161 v = 0.0;
162
163 rtosc_message(msg, 256, path, v == 1.0 ? "T" : "F");
164 } else
165 return;
166
167 if(backend)
168 backend(msg);
169}
170
171float AutomationMgr::getSlot(int slot_id)
172{
173 if(slot_id >= nslots || slot_id < 0)
174 return 0.0;
175 return slots[slot_id].current_state;
176}
177
178
180{
181 if(slot_id >= nslots || slot_id < 0)
182 return;
183 auto &s = slots[slot_id];
184 s.active = false;
185 s.used = false;
186 if(s.learning)
188 for(int i=0; i<nslots; ++i)
189 if(slots[i].learning > s.learning)
190 slots[i].learning--;
191 s.learning = -1;
192 s.midi_cc = -1;
193 s.current_state = 0;
194 memset(s.name, 0, sizeof(s.name));
195 sprintf(s.name, "Slot %d", slot_id);
196 for(int i=0; i<per_slot; ++i)
197 clearSlotSub(slot_id, i);
198 damaged = true;
199}
200
201void AutomationMgr::clearSlotSub(int slot_id, int sub)
202{
203 if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
204 return;
205 auto &a = slots[slot_id].automations[sub];
206 a.used = false;
207 a.active = false;
208 a.relative = false;
209 a.param_base_value = false;
210 memset(a.param_path, 0, sizeof(a.param_path));
211 a.param_type = 0;
212 a.param_min = 0;
213 a.param_max = 0;
214 a.param_step = 0;
215 a.map.gain = 100;
216 a.map.offset = 0;
217
218 damaged = true;
219}
220
221void AutomationMgr::setSlotSubGain(int slot_id, int sub, float f)
222{
223 if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
224 return;
225 auto &m = slots[slot_id].automations[sub].map;
226 m.gain = f;
227}
228float AutomationMgr::getSlotSubGain(int slot_id, int sub)
229{
230 if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
231 return 0.0;
232 auto &m = slots[slot_id].automations[sub].map;
233 return m.gain;
234}
235void AutomationMgr::setSlotSubOffset(int slot_id, int sub, float f)
236{
237 if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
238 return;
239 auto &m = slots[slot_id].automations[sub].map;
240 m.offset = f;
241}
242float AutomationMgr::getSlotSubOffset(int slot_id, int sub)
243{
244 if(slot_id >= nslots || slot_id < 0 || sub >= per_slot || sub < 0)
245 return 0.0;
246 auto &m = slots[slot_id].automations[sub].map;
247 return m.offset;
248}
249
250void AutomationMgr::setName(int slot_id, const char *msg)
251{
252 if(slot_id >= nslots || slot_id < 0)
253 return;
254 strncpy(slots[slot_id].name, msg, sizeof(slots[slot_id].name));
255 damaged = 1;
256}
257const char *AutomationMgr::getName(int slot_id)
258{
259 if(slot_id >= nslots || slot_id < 0)
260 return "";
261 return slots[slot_id].name;
262}
263bool AutomationMgr::handleMidi(int channel, int cc, int val)
264{
265 int ccid = channel*128 + cc;
266
267 bool bound_cc = false;
268 for(int i=0; i<nslots; ++i) {
269 if(slots[i].midi_cc == ccid) {
270 bound_cc = true;
271 setSlot(i, val/127.0);
272 }
273 }
274
275 if(bound_cc)
276 return 1;
277
278 //No bound CC, now to see if there's something to learn
279 for(int i=0; i<nslots; ++i) {
280 if(slots[i].learning == 1) {
281 slots[i].learning = -1;
282 slots[i].midi_cc = ccid;
283 for(int j=0; j<nslots; ++j)
284 if(slots[j].learning > 1)
285 slots[j].learning -= 1;
287 setSlot(i, val/127.0);
288 damaged = 1;
289 break;
290 }
291 }
292 return 0;
293}
294
295void AutomationMgr::set_ports(const struct Ports &p_) {
296 p = &p_;
297};
298//
299// AutomationSlot *slots;
300// struct AutomationMgrImpl *impl;
301//};
303{
304 this->instance = v;
305}
306
307void AutomationMgr::simpleSlope(int slot_id, int par, float slope, float offset)
308{
309 if(slot_id >= nslots || slot_id < 0 || par >= per_slot || par < 0)
310 return;
311 auto &map = slots[slot_id].automations[par].map;
312 map.upoints = 2;
313 map.control_points[0] = 0;
314 map.control_points[1] = -(slope/2)+offset;
315 map.control_points[2] = 1;
316 map.control_points[3] = slope/2+offset;
317
318}
319
321{
322 for(int i=0; i<nslots; ++i)
323 if(!slots[i].used)
324 return i;
325 return -1;
326}
#define NULL
Definition CarlaBridgeFormat.cpp:30
assert(0)
uint8_t a
Definition Spc_Cpu.h:141
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
AutomationSlot * slots
Definition automations.h:120
void setSlotSubOffset(int slot_id, int sub, float f)
Definition automations.cpp:235
~AutomationMgr(void)
Definition automations.cpp:28
std::function< void(const char *)> backend
Definition automations.h:129
bool handleMidi(int channel, int cc, int val)
Definition automations.cpp:263
void setSlotSubGain(int slot_id, int sub, float f)
Definition automations.cpp:221
void createBinding(int slot, const char *path, bool start_midi_learn)
Definition automations.cpp:32
const rtosc::Ports * p
Definition automations.h:126
float getSlotSubGain(int slot_id, int sub)
Definition automations.cpp:228
int learn_queue_len
Definition automations.h:124
const char * getName(int slot_id)
Definition automations.cpp:257
void setSlot(int slot_id, float value)
Definition automations.cpp:113
int nslots
Definition automations.h:121
void clearSlotSub(int slot_id, int sub)
Definition automations.cpp:201
int per_slot
Definition automations.h:122
int damaged
Definition automations.h:131
float getSlot(int slot_id)
Definition automations.cpp:171
void setName(int slot_id, const char *msg)
Definition automations.cpp:250
void simpleSlope(int slot, int au, float slope, float offset)
Definition automations.cpp:307
void set_ports(const struct Ports &p)
Definition automations.cpp:295
void updateMapping(int slot, int sub)
Definition automations.cpp:93
int free_slot(void) const
Definition automations.cpp:320
int active_slot
Definition automations.h:123
void set_instance(void *v)
Definition automations.cpp:302
AutomationMgr(int slots, int per_slot, int control_points)
Definition automations.cpp:6
void setSlotSub(int slot_id, int sub, float value)
Definition automations.cpp:123
void * instance
Definition automations.h:127
float getSlotSubOffset(int slot_id, int sub)
Definition automations.cpp:242
void clearSlot(int slot_id)
Definition automations.cpp:179
unsigned * m
Definition inflate.c:1559
register unsigned j
Definition inflate.c:1576
unsigned v[N_MAX]
Definition inflate.c:1584
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
unsigned f
Definition inflate.c:1572
static PuglViewHint int value
Definition pugl.h:1708
static const char * name
Definition pugl.h:1582
int val
Definition jpeglib.h:956
const char * msg
Definition missing_descriptor.c:20
Definition globals.h:37
size_t rtosc_message(char *buffer, size_t len, const char *address, const char *arguments,...)
Definition rtosc.c:161
Definition automations.h:25
Definition automations.h:48
Definition ports.h:99
Definition ports.h:161
b
Definition crypt.c:628
else sprintf(d_t_str, LoadFarString(shtYMDHMTime), yr%100, monthstr, dy, hh, mm)