8b2077fb5bb813cf50a4292c5fb18387dd4b4ad9
[ardour.git] / libs / surfaces / generic_midi / midicontrollable.cc
1 /*
2     Copyright (C) 1998-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <cstdio> /* for sprintf, sigh */
21 #include <climits>
22 #include "pbd/error.h"
23 #include "pbd/xml++.h"
24 #include "midi++/port.h"
25 #include "midi++/channel.h"
26 #include "ardour/automation_control.h"
27
28 #include "midicontrollable.h"
29
30 using namespace sigc;
31 using namespace MIDI;
32 using namespace PBD;
33 using namespace ARDOUR;
34
35 MIDIControllable::MIDIControllable (Port& p, const string& c, bool is_bistate)
36         : controllable (0), _port (p), bistate (is_bistate)
37 {
38         init ();
39 }
40
41 MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate)
42         : controllable (&c), _current_uri (c.uri()), _port (p), bistate (is_bistate)
43 {
44         init ();
45 }
46
47 MIDIControllable::~MIDIControllable ()
48 {
49         drop_external_control ();
50 }
51
52 void
53 MIDIControllable::init ()
54 {
55         setting = false;
56         last_value = 0; // got a better idea ?
57         control_type = none;
58         _control_description = "MIDI Control: none";
59         control_additional = (byte) -1;
60         connections = 0;
61         feedback = true; // for now
62
63         /* use channel 0 ("1") as the initial channel */
64
65         midi_rebind (0);
66 }
67
68 void
69 MIDIControllable::midi_forget ()
70 {
71         /* stop listening for incoming messages, but retain
72            our existing event + type information.
73         */
74
75         if (connections > 0) {
76                 midi_sense_connection[0].disconnect ();
77         }
78
79         if (connections > 1) {
80                 midi_sense_connection[1].disconnect ();
81         }
82
83         connections = 0;
84         midi_learn_connection.disconnect ();
85
86 }
87
88 void
89 MIDIControllable::reacquire_controllable ()
90 {
91         _controllable = Controllable::controllable_by_uri (current_uri);
92 }
93
94 void
95 MIDIControllable::midi_rebind (channel_t c)
96 {
97         if (c >= 0) {
98                 bind_midi (c, control_type, control_additional);
99         } else {
100                 midi_forget ();
101         }
102 }
103
104 void
105 MIDIControllable::learn_about_external_control ()
106 {
107         drop_external_control ();
108         midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver));
109 }
110
111 void
112 MIDIControllable::stop_learning ()
113 {
114         midi_learn_connection.disconnect ();
115 }
116
117 void
118 MIDIControllable::drop_external_control ()
119 {
120         if (connections > 0) {
121                 midi_sense_connection[0].disconnect ();
122         }
123         if (connections > 1) {
124                 midi_sense_connection[1].disconnect ();
125         }
126
127         connections = 0;
128         midi_learn_connection.disconnect ();
129
130         control_type = none;
131         control_additional = (byte) -1;
132 }
133
134 float
135 MIDIControllable::control_to_midi(float val)
136 {
137         float control_min = 0.0f;
138         float control_max = 1.0f;
139         ARDOUR::AutomationControl* ac = dynamic_cast<ARDOUR::AutomationControl*>(&controllable);
140         if (ac) {
141                 control_min = ac->parameter().min();
142                 control_max = ac->parameter().max();
143         }
144
145         const float control_range = control_max - control_min;
146         const float midi_range    = 127.0f; // TODO: NRPN etc.
147
148         return (val - control_min) / control_range * midi_range;
149 }
150
151 float
152 MIDIControllable::midi_to_control(float val)
153 {
154         float control_min = 0.0f;
155         float control_max = 1.0f;
156         ARDOUR::AutomationControl* ac = dynamic_cast<ARDOUR::AutomationControl*>(&controllable);
157         if (ac) {
158                 control_min = ac->parameter().min();
159                 control_max = ac->parameter().max();
160         }
161
162         const float control_range = control_max - control_min;
163         const float midi_range    = 127.0f; // TODO: NRPN etc.
164
165         return val / midi_range * control_range + control_min;
166 }
167
168 void
169 MIDIControllable::midi_sense_note_on (Parser &p, EventTwoBytes *tb)
170 {
171         midi_sense_note (p, tb, true);
172 }
173
174 void
175 MIDIControllable::midi_sense_note_off (Parser &p, EventTwoBytes *tb)
176 {
177         midi_sense_note (p, tb, false);
178 }
179
180 void
181 MIDIControllable::midi_sense_note (Parser &, EventTwoBytes *msg, bool is_on)
182 {
183         if (!controllable) { 
184                 return;
185         }
186
187         if (!bistate) {
188                 controllable->set_value (msg->note_number/127.0);
189         } else {
190
191                 /* Note: parser handles the use of zero velocity to
192                    mean note off. if we get called with is_on=true, then we
193                    got a *real* note on.
194                 */
195
196                 if (msg->note_number == control_additional) {
197                         controllable.set_value (is_on ? 1 : 0);
198                 }
199         }
200
201         last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights
202 }
203
204 void
205 MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg)
206 {
207         if (!controllable) { 
208                 return;
209         }
210
211         if (controllable->touching()) {
212                 return; // to prevent feedback fights when e.g. dragging a UI slider
213         }
214
215         if (control_additional == msg->controller_number) {
216                 if (!bistate) {
217                         controllable->set_value (midi_to_control(msg->value));
218                 } else {
219                         if (msg->value > 64.0) {
220                                 controllable->set_value (1);
221                         } else {
222                                 controllable->set_value (0);
223                         }
224                 }
225
226                 last_value = (MIDI::byte) (control_to_midi(controllable->get_value())); // to prevent feedback fights
227         }
228 }
229
230 void
231 MIDIControllable::midi_sense_program_change (Parser &, byte msg)
232 {
233         if (!controllable) { 
234                 return;
235         }
236         /* XXX program change messages make no sense for bistates */
237
238         if (!bistate) {
239                 controllable->set_value (msg/127.0);
240                 last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights
241         }
242 }
243
244 void
245 MIDIControllable::midi_sense_pitchbend (Parser &, pitchbend_t pb)
246 {
247         if (!controllable) { 
248                 return;
249         }
250
251         /* pitchbend messages make no sense for bistates */
252
253         /* XXX gack - get rid of assumption about typeof pitchbend_t */
254
255         controllable->set_value ((pb/(float) SHRT_MAX));
256         last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights
257 }
258
259 void
260 MIDIControllable::midi_receiver (Parser &, byte *msg, size_t /*len*/)
261 {
262         /* we only respond to channel messages */
263
264         if ((msg[0] & 0xF0) < 0x80 || (msg[0] & 0xF0) > 0xE0) {
265                 return;
266         }
267
268         /* if the our port doesn't do input anymore, forget it ... */
269
270         if (!_port.input()) {
271                 return;
272         }
273
274         bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
275
276         controllable->LearningFinished ();
277 }
278
279 void
280 MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
281 {
282         char buf[64];
283
284         drop_external_control ();
285
286         control_type = ev;
287         control_channel = chn;
288         control_additional = additional;
289
290         if (_port.input() == 0) {
291                 return;
292         }
293
294         Parser& p = *_port.input();
295
296         int chn_i = chn;
297         switch (ev) {
298         case MIDI::off:
299                 midi_sense_connection[0] = p.channel_note_off[chn_i].connect
300                         (mem_fun (*this, &MIDIControllable::midi_sense_note_off));
301
302                 /* if this is a bistate, connect to noteOn as well,
303                    and we'll toggle back and forth between the two.
304                 */
305
306                 if (bistate) {
307                         midi_sense_connection[1] = p.channel_note_on[chn_i].connect
308                                 (mem_fun (*this, &MIDIControllable::midi_sense_note_on));
309                         connections = 2;
310                 } else {
311                         connections = 1;
312                 }
313                 _control_description = "MIDI control: NoteOff";
314                 break;
315
316         case MIDI::on:
317                 midi_sense_connection[0] = p.channel_note_on[chn_i].connect
318                         (mem_fun (*this, &MIDIControllable::midi_sense_note_on));
319                 if (bistate) {
320                         midi_sense_connection[1] = p.channel_note_off[chn_i].connect
321                                 (mem_fun (*this, &MIDIControllable::midi_sense_note_off));
322                         connections = 2;
323                 } else {
324                         connections = 1;
325                 }
326                 _control_description = "MIDI control: NoteOn";
327                 break;
328
329         case MIDI::controller:
330                 midi_sense_connection[0] = p.channel_controller[chn_i].connect
331                         (mem_fun (*this, &MIDIControllable::midi_sense_controller));
332                 connections = 1;
333                 snprintf (buf, sizeof (buf), "MIDI control: Controller %d", control_additional);
334                 _control_description = buf;
335                 break;
336
337         case MIDI::program:
338                 if (!bistate) {
339                         midi_sense_connection[0] = p.channel_program_change[chn_i].connect
340                                 (mem_fun (*this,
341                                        &MIDIControllable::midi_sense_program_change));
342                         connections = 1;
343                         _control_description = "MIDI control: ProgramChange";
344                 }
345                 break;
346
347         case MIDI::pitchbend:
348                 if (!bistate) {
349                         midi_sense_connection[0] = p.channel_pitchbend[chn_i].connect
350                                 (mem_fun (*this, &MIDIControllable::midi_sense_pitchbend));
351                         connections = 1;
352                         _control_description = "MIDI control: Pitchbend";
353                 }
354                 break;
355
356         default:
357                 break;
358         }
359 }
360
361 void
362 MIDIControllable::send_feedback ()
363 {
364         byte msg[3];
365
366         if (setting || !feedback || control_type == none) {
367                 return;
368         }
369
370         msg[0] = (control_type & 0xF0) | (control_channel & 0xF);
371         msg[1] = control_additional;
372         msg[2] = (byte) (control_to_midi(controllable->get_value()));
373
374         _port.write (msg, 3, 0);
375 }
376
377 MIDI::byte*
378 MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool /*force*/)
379 {
380         if (control_type != none && feedback && bufsize > 2) {
381
382                 MIDI::byte gm = (MIDI::byte) (control_to_midi(controllable->get_value()));
383
384                 if (gm != last_value) {
385                         *buf++ = (0xF0 & control_type) | (0xF & control_channel);
386                         *buf++ = control_additional; /* controller number */
387                         *buf++ = gm;
388                         last_value = gm;
389                         bufsize -= 3;
390                 }
391         }
392
393         return buf;
394 }
395
396 int
397 MIDIControllable::set_state (const XMLNode& node, int /*version*/)
398 {
399         const XMLProperty* prop;
400         int xx;
401
402         if ((prop = node.property ("event")) != 0) {
403                 sscanf (prop->value().c_str(), "0x%x", &xx);
404                 control_type = (MIDI::eventType) xx;
405         } else {
406                 return -1;
407         }
408
409         if ((prop = node.property ("channel")) != 0) {
410                 sscanf (prop->value().c_str(), "%d", &xx);
411                 control_channel = (MIDI::channel_t) xx;
412         } else {
413                 return -1;
414         }
415
416         if ((prop = node.property ("additional")) != 0) {
417                 sscanf (prop->value().c_str(), "0x%x", &xx);
418                 control_additional = (MIDI::byte) xx;
419         } else {
420                 return -1;
421         }
422
423         if ((prop = node.property ("feedback")) != 0) {
424                 feedback = (prop->value() == "yes");
425         } else {
426                 feedback = true; // default
427         }
428
429         bind_midi (control_channel, control_type, control_additional);
430
431         return 0;
432 }
433
434 XMLNode&
435 MIDIControllable::get_state ()
436 {
437         if (!controllable) {
438                 return XXX !what!;
439         }
440
441         char buf[32];
442         XMLNode& node (controllable->get_state ());
443
444         snprintf (buf, sizeof(buf), "0x%x", (int) control_type);
445         node.add_property ("event", buf);
446         snprintf (buf, sizeof(buf), "%d", (int) control_channel);
447         node.add_property ("channel", buf);
448         snprintf (buf, sizeof(buf), "0x%x", (int) control_additional);
449         node.add_property ("additional", buf);
450         node.add_property ("feedback", (feedback ? "yes" : "no"));
451
452         return node;
453 }
454