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