1 /*
2 * Copyright (C) 2010-2015 Paul Davis <paul@linuxaudiosystems.com>
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 along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
MIDIInvokable(MIDI::Parser & p)28 MIDIInvokable::MIDIInvokable (MIDI::Parser& p)
29 : _parser (p)
30 {
31 data_size = 0;
32 data = 0;
33 }
34
~MIDIInvokable()35 MIDIInvokable::~MIDIInvokable ()
36 {
37 delete [] data;
38 }
39
40 int
init(GenericMidiControlProtocol & ui,const std::string & name,MIDI::byte * msg_data,size_t data_sz)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
midi_sense_note_on(Parser & p,EventTwoBytes * tb)56 MIDIInvokable::midi_sense_note_on (Parser &p, EventTwoBytes *tb)
57 {
58 midi_sense_note (p, tb, true);
59 }
60
61 void
midi_sense_note_off(Parser & p,EventTwoBytes * tb)62 MIDIInvokable::midi_sense_note_off (Parser &p, EventTwoBytes *tb)
63 {
64 midi_sense_note (p, tb, false);
65 }
66
67 void
midi_sense_note(Parser &,EventTwoBytes * msg,bool)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
midi_sense_controller(Parser &,EventTwoBytes * msg)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
midi_sense_program_change(Parser &,byte msg)84 MIDIInvokable::midi_sense_program_change (Parser &, byte msg)
85 {
86 if (msg == control_additional) {
87 execute ();
88 }
89 }
90
91 void
midi_sense_sysex(Parser &,byte * msg,size_t sz)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
midi_sense_any(Parser &,byte * msg,size_t sz)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
bind_midi(channel_t chn,eventType ev,MIDI::byte additional)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
166