/[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 392 - (show annotations) (download)
Sat Feb 19 02:40:24 2005 UTC (19 years, 1 month ago) by schoenebeck
File size: 10699 byte(s)
* fixed possibility that memory got not locked
* immediately set instrument status when calling LOAD INSTUMENT NON_MODAL

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

  ViewVC Help
Powered by ViewVC