/[svn]/linuxsampler/trunk/src/drivers/midi/MidiInputDeviceJack.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/midi/MidiInputDeviceJack.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1715 - (show annotations) (download)
Tue Mar 11 15:20:46 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 11231 byte(s)
* dispatch bank select as ordinary CC as well, the user might seriously
  want to (mis)use it for some purpose ("fixed" in all current MIDI
  input drivers: ALSA, CoreMIDI, JACK, MidiShare, MME)
* minor fix: only mark FX sends as being modified if really the
  respective FX send MIDI controller was used

1 /***************************************************************************
2 * *
3 * Copyright (C) 2008 Andreas Persson *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
18 * MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #include "MidiInputDeviceJack.h"
22 #include "../../common/global_private.h"
23 #include "../audio/AudioOutputDeviceJack.h"
24 #include <errno.h>
25
26 #ifndef HAVE_JACK_MIDI_GET_EVENT_COUNT
27 #define jack_midi_get_event_count(port_buf, nframes) jack_midi_port_get_info(port_buf, nframes)->event_count
28 #endif
29
30 namespace LinuxSampler {
31
32 /// number of currently existing JACK midi input devices in LinuxSampler
33 static int existingJackDevices = 0;
34
35 // *************** MidiInputPortJack::ParameterName ***************
36 // *
37
38 MidiInputDeviceJack::MidiInputPortJack::ParameterName::ParameterName(MidiInputPortJack* pPort) throw (Exception) : MidiInputPort::ParameterName(pPort, "midi_in_" + ToString(pPort->GetPortNumber())) {
39 this->pPort = pPort;
40 }
41
42 void MidiInputDeviceJack::MidiInputPortJack::ParameterName::OnSetValue(String s) throw (Exception) {
43 if (jack_port_set_name(pPort->hJackPort, s.c_str())) throw Exception("Failed to rename JACK port");
44 }
45
46
47 // *************** MidiInputPortJack::ParameterJackBindings ***************
48 // *
49
50 MidiInputDeviceJack::MidiInputPortJack::ParameterJackBindings::ParameterJackBindings(MidiInputPortJack* pPort) : DeviceRuntimeParameterStrings(std::vector<String>()) {
51 this->pPort = pPort;
52 }
53
54 String MidiInputDeviceJack::MidiInputPortJack::ParameterJackBindings::Description() {
55 return "Bindings to other JACK clients";
56 }
57
58 bool MidiInputDeviceJack::MidiInputPortJack::ParameterJackBindings::Fix() {
59 return false;
60 }
61
62 std::vector<String> MidiInputDeviceJack::MidiInputPortJack::ParameterJackBindings::PossibilitiesAsString() {
63 const char** pPortNames = jack_get_ports(pPort->pDevice->hJackClient, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput);
64 if (!pPortNames) return std::vector<String>();
65 std::vector<String> result;
66 for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);
67 free(pPortNames);
68 return result;
69 }
70
71 void MidiInputDeviceJack::MidiInputPortJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {
72 String dst_name = ((DeviceCreationParameterString*)pPort->pDevice->Parameters["NAME"])->ValueAsString() + ":" +
73 ((DeviceRuntimeParameterString*)pPort->Parameters["NAME"])->ValueAsString();
74 // disconnect all current bindings first
75 for (int i = 0; i < Bindings.size(); i++) {
76 String src_name = Bindings[i];
77 int res = jack_disconnect(pPort->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
78 }
79 // connect new bindings
80 for (int i = 0; i < vS.size(); i++) {
81 String src_name = vS[i];
82 int res = jack_connect(pPort->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
83 if (res == EEXIST) throw MidiInputException("Jack: Connection to port '" + dst_name + "' already established");
84 else if (res) throw MidiInputException("Jack: Cannot connect port '" + src_name + "' to port '" + dst_name + "'");
85 }
86 // remember bindings
87 Bindings = vS;
88 }
89
90 String MidiInputDeviceJack::MidiInputPortJack::ParameterJackBindings::Name() {
91 return "JACK_BINDINGS";
92 }
93
94
95
96 // *************** MidiInputPortJack ***************
97 // *
98
99 MidiInputDeviceJack::MidiInputPortJack::MidiInputPortJack(MidiInputDeviceJack* pDevice) throw (MidiInputException) : MidiInputPort(pDevice, pDevice->Ports.size()) {
100 this->pDevice = pDevice;
101
102 String port_id = "midi_in_" + ToString(portNumber);
103 hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
104 if (!hJackPort) throw MidiInputException("Jack: Cannot register Jack MIDI input port.");
105
106 delete Parameters["NAME"];
107 Parameters["NAME"] = new ParameterName(this);
108 Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
109 }
110
111 MidiInputDeviceJack::MidiInputPortJack::~MidiInputPortJack() {
112 jack_port_unregister(pDevice->hJackClient, hJackPort);
113 }
114
115
116 // *************** MidiInputDeviceJack::ParameterName ***************
117 // *
118
119 MidiInputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
120 InitWithDefault(); // use default name
121 }
122
123 MidiInputDeviceJack::ParameterName::ParameterName(String s) : DeviceCreationParameterString(s) {
124 }
125
126 String MidiInputDeviceJack::ParameterName::Description() {
127 return "Arbitrary JACK client name";
128 }
129
130 bool MidiInputDeviceJack::ParameterName::Fix() {
131 return true;
132 }
133
134 bool MidiInputDeviceJack::ParameterName::Mandatory() {
135 return false;
136 }
137
138 std::map<String,DeviceCreationParameter*> MidiInputDeviceJack::ParameterName::DependsAsParameters() {
139 return std::map<String,DeviceCreationParameter*>(); // no dependencies
140 }
141
142 std::vector<String> MidiInputDeviceJack::ParameterName::PossibilitiesAsString(std::map<String,String> Parameters) {
143 return std::vector<String>();
144 }
145
146 optional<String> MidiInputDeviceJack::ParameterName::DefaultAsString(std::map<String,String> Parameters) {
147 return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
148 }
149
150 void MidiInputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
151 // not possible, as parameter is fix
152 }
153
154 String MidiInputDeviceJack::ParameterName::Name() {
155 return "NAME";
156 }
157
158
159
160 // *************** MidiInputDeviceJack ***************
161 // *
162
163 MidiInputDeviceJack::MidiInputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler) {
164 pJackClient = JackClient::CreateMidi(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
165 hJackClient = pJackClient->hJackClient;
166 existingJackDevices++;
167
168 AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
169 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
170 Listen();
171 }
172 }
173
174 MidiInputDeviceJack::~MidiInputDeviceJack() {
175 StopListen();
176 // free the midi ports (we can't let the base class do this,
177 // as the MidiInputPortJack destructors need access to
178 // hJackClient)
179 for (std::map<int,MidiInputPort*>::iterator iter = Ports.begin(); iter != Ports.end() ; iter++) {
180 delete static_cast<MidiInputPortJack*>(iter->second);
181 }
182 Ports.clear();
183
184 JackClient::ReleaseMidi(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
185 existingJackDevices--;
186 }
187
188 MidiInputDeviceJack::MidiInputPortJack* MidiInputDeviceJack::CreateMidiPort() {
189 return new MidiInputPortJack(this);
190 }
191
192 String MidiInputDeviceJack::Name() {
193 return "JACK";
194 }
195
196 String MidiInputDeviceJack::Driver() {
197 return Name();
198 }
199
200 void MidiInputDeviceJack::Listen() {
201 pJackClient->SetMidiInputDevice(this);
202 }
203
204 void MidiInputDeviceJack::StopListen() {
205 pJackClient->SetMidiInputDevice(0);
206 }
207
208 String MidiInputDeviceJack::Description() {
209 return "JACK Audio Connection Kit";
210 }
211
212 String MidiInputDeviceJack::Version() {
213 String s = "$Revision: 1.2 $";
214 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
215 }
216
217 void MidiInputDeviceJack::Process(int nsamples) {
218 int nbPorts = Ports.size();
219 for (int i = 0 ; i < nbPorts ; i++) {
220 MidiInputPortJack* port = static_cast<MidiInputPortJack*>(Ports[i]);
221 void* port_buffer = jack_port_get_buffer(port->hJackPort, nsamples);
222
223 #if JACK_MIDI_FUNCS_NEED_NFRAMES
224 int event_count = jack_midi_get_event_count(port_buffer, nsamples); // old jack version
225 #else
226 int event_count = jack_midi_get_event_count(port_buffer);
227 #endif
228 for (int i = 0 ; i < event_count ; i++)
229 {
230 jack_midi_event_t ev;
231 #if JACK_MIDI_FUNCS_NEED_NFRAMES
232 jack_midi_event_get(&ev, port_buffer, i, nsamples); // old jack version
233 #else
234 jack_midi_event_get(&ev, port_buffer, i);
235 #endif
236 uint8_t* data = ev.buffer;
237 uint8_t channel = data[0] & 0x0f;
238 switch (data[0] & 0xf0) {
239 case 0xb0:
240 if (data[1] == 0) {
241 port->DispatchBankSelectMsb(data[2], channel);
242 } else if (data[1] == 32) {
243 port->DispatchBankSelectLsb(data[2], channel);
244 }
245 port->DispatchControlChange(data[1], data[2], channel, ev.time);
246 break;
247
248 case 0xd0:
249 port->DispatchControlChange(128, data[1], channel, ev.time);
250 break;
251
252 case 0xe0:
253 port->DispatchPitchbend(data[1], channel, ev.time);
254 break;
255
256 case 0x90:
257 if (data[2]) {
258 port->DispatchNoteOn(data[1], data[2], channel, ev.time);
259 } else {
260 port->DispatchNoteOff(data[1], data[2], channel, ev.time);
261 }
262 break;
263
264 case 0x80:
265 port->DispatchNoteOff(data[1], data[2], channel, ev.time);
266 break;
267
268 case 0xc0:
269 port->DispatchProgramChange(data[1], channel);
270 break;
271 }
272 }
273 }
274 }
275 }

  ViewVC Help
Powered by ViewVC