Trim midi++ port code to either do in or out, but not both in the same object.
[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::Port& p)
29         : _port (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) {
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         if (_port.parser() == 0) {
131                 return;
132         }
133
134         Parser& p = *_port.parser();
135
136         int chn_i = chn;
137
138         /* incoming MIDI is parsed by Ardour' MidiUI event loop/thread, and we want our handlers to execute in that context, so we use
139            Signal::connect_same_thread() here.
140         */
141
142         switch (ev) {
143         case MIDI::off:
144                 p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2));
145                 break;
146
147         case MIDI::on:
148                 p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2));
149                 break;
150                 
151         case MIDI::controller:
152                 p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2));
153                 break;
154
155         case MIDI::program:
156                 p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2));
157                 break;
158
159         case MIDI::sysex:
160                 p.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3));
161                 break;
162
163         case MIDI::any:
164                 p.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3));
165                 break;
166
167         default:
168                 break;
169         }
170 }
171