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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 551 - (show annotations) (download)
Tue May 17 18:16:54 2005 UTC (18 years, 11 months ago) by schoenebeck
File size: 11743 byte(s)
* Implemented MIDI program change as general, engine independant solution.
  The program number will determine the sampler channel to which the MIDI
  device will be connected to and the given MIDI channel defines on which
  MIDI channel that sampler channel should listen to. Also the program
  change will disconnect probably established connection from the previous
  program change event.

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include "MidiInputDeviceAlsa.h"
25 #include "MidiInputDeviceFactory.h"
26
27 #define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
28
29 namespace LinuxSampler {
30
31 // *************** ParameterName ***************
32 // *
33
34 MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::ParameterName(MidiInputPort* pPort) throw (LinuxSamplerException) : MidiInputPort::ParameterName(pPort, "Port " + ToString(pPort->GetPortNumber())) {
35 OnSetValue(ValueAsString()); // initialize port name
36 }
37
38 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {
39 if (s.size() > 16) throw LinuxSamplerException("Name too long for ALSA MIDI input port (max. 16 characters)");
40 snd_seq_port_info_t* hInfo;
41 snd_seq_port_info_malloc(&hInfo);
42 snd_seq_get_port_info(((MidiInputDeviceAlsa*)pPort->GetDevice())->hAlsaSeq, pPort->GetPortNumber(), hInfo);
43 snd_seq_port_info_set_name(hInfo, s.c_str());
44 snd_seq_set_port_info(((MidiInputDeviceAlsa*)pPort->GetDevice())->hAlsaSeq, pPort->GetPortNumber(), hInfo);
45 snd_seq_port_info_free(hInfo);
46 }
47
48
49
50 // *************** ParameterAlsaSeqBindings ***************
51 // *
52
53
54 MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::ParameterAlsaSeqBindings(MidiInputPortAlsa* pPort) : DeviceRuntimeParameterStrings( std::vector<String>() ) {
55 this->pPort = pPort;
56 }
57
58 String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Description() {
59 return "Bindings to other Alsa sequencer clients";
60 }
61 bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Fix() {
62 return false;
63 }
64
65 std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::PossibilitiesAsString() {
66 std::vector<String> res;
67 snd_seq_client_info_t* cinfo;
68 snd_seq_port_info_t* pinfo;
69
70 snd_seq_client_info_alloca(&cinfo);
71 snd_seq_port_info_alloca(&pinfo);
72 snd_seq_client_info_set_client(cinfo, -1);
73 while (snd_seq_query_next_client(pPort->pDevice->hAlsaSeq, cinfo) >= 0) {
74 snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
75 snd_seq_port_info_set_port(pinfo, -1);
76 while (snd_seq_query_next_port(pPort->pDevice->hAlsaSeq, pinfo) >= 0) {
77 if (perm_ok(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ)) {
78 String seq_id = ToString(snd_seq_client_info_get_client(cinfo)) + ":" +
79 ToString(snd_seq_port_info_get_port(pinfo));
80 res.push_back(seq_id);
81 }
82 }
83 }
84
85 return res;
86 }
87
88 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::OnSetValue(std::vector<String> vS) throw (LinuxSamplerException) {
89 std::vector<String>::iterator iter = vS.begin();
90 for (; iter != vS.end(); iter++) pPort->ConnectToAlsaMidiSource((*iter).c_str());
91 }
92
93
94
95 // *************** ParameterAlsaSeqId ***************
96 // *
97
98 MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::ParameterAlsaSeqId(MidiInputPortAlsa* pPort)
99 : DeviceRuntimeParameterString(ToString(pPort->pDevice->hAlsaSeqClient) + ":" + ToString(pPort->portNumber)) {
100 }
101
102 String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::Description() {
103 return "ALSA Sequencer ID";
104 }
105
106 bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::Fix() {
107 return true;
108 }
109
110 std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::PossibilitiesAsString() {
111 return std::vector<String>(); // nothing
112 }
113
114 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::OnSetValue(String s) {
115 // not possible as parameter is 'fix'
116 }
117
118
119
120 // *************** MidiInputPortAlsa ***************
121 // *
122
123 MidiInputDeviceAlsa::MidiInputPortAlsa::MidiInputPortAlsa(MidiInputDeviceAlsa* pDevice) throw (MidiInputException) : MidiInputPort(pDevice, -1) {
124 this->pDevice = pDevice;
125
126 // create Alsa sequencer port
127 int alsaPort = snd_seq_create_simple_port(pDevice->hAlsaSeq, "unnamed port",
128 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
129 SND_SEQ_PORT_TYPE_APPLICATION);
130 if (alsaPort < 0) throw MidiInputException("Error creating sequencer port");
131 this->portNumber = alsaPort;
132
133 Parameters["NAME"] = new ParameterName(this);
134 Parameters["ALSA_SEQ_BINDINGS"] = new ParameterAlsaSeqBindings(this);
135 Parameters["ALSA_SEQ_ID"] = new ParameterAlsaSeqId(this);
136 }
137
138 MidiInputDeviceAlsa::MidiInputPortAlsa::~MidiInputPortAlsa() {
139 snd_seq_delete_simple_port(pDevice->hAlsaSeq, portNumber);
140 }
141
142 /**
143 * Connects this Alsa midi input device with an Alsa MIDI source.
144 *
145 * @param Client - Alsa sequencer client and port ID of a MIDI source
146 * (e.g. "64:0")
147 * @throws MidiInputException if connection cannot be established
148 */
149 void MidiInputDeviceAlsa::MidiInputPortAlsa::ConnectToAlsaMidiSource(const char* MidiSource) {
150 snd_seq_addr_t sender, dest;
151 snd_seq_port_subscribe_t* subs;
152 int hExtClient, hExtPort;
153
154 sscanf(MidiSource, "%d:%d", &hExtClient, &hExtPort);
155 sender.client = (char) hExtClient;
156 sender.port = (char) hExtPort;
157 dest.client = (char) pDevice->hAlsaSeqClient;
158 dest.port = (char) portNumber;
159 snd_seq_port_subscribe_alloca(&subs);
160 snd_seq_port_subscribe_set_sender(subs, &sender);
161 snd_seq_port_subscribe_set_dest(subs, &dest);
162 snd_seq_port_subscribe_set_queue(subs, 1);
163 snd_seq_port_subscribe_set_time_update(subs, 1);
164 snd_seq_port_subscribe_set_time_real(subs, 1);
165 if (snd_seq_subscribe_port(pDevice->hAlsaSeq, subs) < 0)
166 throw MidiInputException(String("Unable to connect to Alsa seq client \'") + MidiSource + "\' (" + snd_strerror(errno) + ")");
167 }
168
169
170
171 // *************** MidiInputDeviceAlsa ***************
172 // *
173
174 MidiInputDeviceAlsa::MidiInputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler), Thread(true, true, 1, -1) {
175 if (snd_seq_open(&hAlsaSeq, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
176 throw MidiInputException("Error opening ALSA sequencer");
177 }
178 this->hAlsaSeqClient = snd_seq_client_id(hAlsaSeq);
179 snd_seq_set_client_name(hAlsaSeq, "LinuxSampler");
180 AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
181 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
182 Listen();
183 }
184 }
185
186 MidiInputDeviceAlsa::~MidiInputDeviceAlsa() {
187 snd_seq_close(hAlsaSeq);
188 }
189
190 MidiInputDeviceAlsa::MidiInputPortAlsa* MidiInputDeviceAlsa::CreateMidiPort() {
191 return new MidiInputPortAlsa(this);
192 }
193
194 String MidiInputDeviceAlsa::Name() {
195 return "ALSA";
196 }
197
198 String MidiInputDeviceAlsa::Driver() {
199 return Name();
200 }
201
202 void MidiInputDeviceAlsa::Listen() {
203 StartThread();
204 }
205
206 void MidiInputDeviceAlsa::StopListen() {
207 StopThread();
208 }
209
210 String MidiInputDeviceAlsa::Description() {
211 return "Advanced Linux Sound Architecture";
212 }
213
214 String MidiInputDeviceAlsa::Version() {
215 String s = "$Revision: 1.15 $";
216 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
217 }
218
219 int MidiInputDeviceAlsa::Main() {
220 int npfd;
221 struct pollfd* pfd;
222 snd_seq_event_t* ev;
223
224 npfd = snd_seq_poll_descriptors_count(hAlsaSeq, POLLIN);
225 pfd = (struct pollfd*) alloca(npfd * sizeof(struct pollfd));
226 snd_seq_poll_descriptors(hAlsaSeq, pfd, npfd, POLLIN);
227 while (true) {
228 if (poll(pfd, npfd, 100000) > 0) {
229 do {
230 snd_seq_event_input(hAlsaSeq, &ev);
231 int port = (int) ev->dest.port;
232 MidiInputPort* pMidiInputPort = Ports[port];
233
234 switch (ev->type) {
235 case SND_SEQ_EVENT_CONTROLLER:
236 pMidiInputPort->DispatchControlChange(ev->data.control.param, ev->data.control.value, ev->data.control.channel);
237 break;
238
239 case SND_SEQ_EVENT_PITCHBEND:
240 pMidiInputPort->DispatchPitchbend(ev->data.control.value, ev->data.control.channel);
241 break;
242
243 case SND_SEQ_EVENT_NOTEON:
244 if (ev->data.note.velocity != 0) {
245 pMidiInputPort->DispatchNoteOn(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
246 }
247 else {
248 pMidiInputPort->DispatchNoteOff(ev->data.note.note, 0, ev->data.control.channel);
249 }
250 break;
251
252 case SND_SEQ_EVENT_NOTEOFF:
253 pMidiInputPort->DispatchNoteOff(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
254 break;
255
256 case SND_SEQ_EVENT_SYSEX:
257 pMidiInputPort->DispatchSysex(ev->data.ext.ptr, ev->data.ext.len);
258 break;
259
260 case SND_SEQ_EVENT_PGMCHANGE:
261 pMidiInputPort->DispatchProgramChange(ev->data.control.value, ev->data.control.channel);
262 break;
263 }
264 snd_seq_free_event(ev);
265 } while (snd_seq_event_input_pending(hAlsaSeq, 0) > 0);
266 }
267 }
268 }
269
270 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC