mackie: more debug tracing
[ardour.git] / libs / surfaces / generic_midi / midiinvokable.cc
1 /*
2     Copyright (C) 2009 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 #include <cstring>
20
21 #include "midi++/port.h"
22
23 #include "midifunction.h"
24 #include "generic_midi_control_protocol.h"
25
26 using namespace MIDI;
27
28 MIDIInvokable::MIDIInvokable (MIDI::Parser& p)
29         : _parser (p)
30 {
31         data_size = 0;
32         data = 0;
33 }
34
35 MIDIInvokable::~MIDIInvokable ()
36 {
37         delete [] data;
38 }
39
40 int
41 MIDIInvokable::init (GenericMidiControlProtocol& ui, const std::string& name, MIDI::byte* msg_data, size_t data_sz)
42 {
43         _ui = &ui;
44         _invokable_name = name;
45
46         if (data_sz) {
47                 /* we take ownership of the sysex data */
48                 data = msg_data;
49                 data_size = data_sz;
50         }
51
52         return 0;
53 }
54
55 void
56 MIDIInvokable::midi_sense_note_on (Parser &p, EventTwoBytes *tb)
57 {
58         midi_sense_note (p, tb, true);
59 }
60
61 void
62 MIDIInvokable::midi_sense_note_off (Parser &p, EventTwoBytes *tb)
63 {
64         midi_sense_note (p, tb, false);
65 }
66
67 void
68 MIDIInvokable::midi_sense_note (Parser &, EventTwoBytes *msg, bool /* is_on */)
69 {
70         if (msg->note_number == control_additional) {
71                 execute ();
72         }
73 }
74
75 void
76 MIDIInvokable::midi_sense_controller (Parser &, EventTwoBytes *msg)
77 {
78         if (control_additional == msg->controller_number && msg->value > 0x40 ) {
79                 execute ();
80         }
81 }
82
83 void
84 MIDIInvokable::midi_sense_program_change (Parser &, byte msg)
85 {
86         if (msg == control_additional) {
87                 execute ();
88         }
89 }
90
91 void
92 MIDIInvokable::midi_sense_sysex (Parser &, byte* msg, size_t sz)
93 {
94         if (sz != data_size) {
95                 return;
96         }
97
98         if (memcmp (msg, data, data_size) != 0) {
99                 return;
100         }
101
102         execute ();
103 }
104
105 void
106 MIDIInvokable::midi_sense_any (Parser &, byte* msg, size_t sz)
107 {
108         if (sz != data_size) {
109                 return;
110         }
111
112         if (memcmp (msg, data, data_size) != 0) {
113                 return;
114         }
115
116         execute ();
117 }
118
119
120 void
121 MIDIInvokable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
122 {
123         midi_sense_connection[0].disconnect ();
124         midi_sense_connection[1].disconnect ();
125
126         control_type = ev;
127         control_channel = chn;
128         control_additional = additional;
129
130         int chn_i = chn;
131
132         /* incoming MIDI is parsed by Ardour' MidiUI event loop/thread, and we want our handlers to execute in that context, so we use
133            Signal::connect_same_thread() here.
134         */
135
136         switch (ev) {
137         case MIDI::off:
138                 _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2));
139                 break;
140
141         case MIDI::on:
142                 _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2));
143                 break;
144
145         case MIDI::controller:
146                 _parser.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2));
147                 break;
148
149         case MIDI::program:
150                 _parser.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2));
151                 break;
152
153         case MIDI::sysex:
154                 _parser.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3));
155                 break;
156
157         case MIDI::any:
158                 _parser.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3));
159                 break;
160
161         default:
162                 break;
163         }
164 }
165