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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1951 - (hide annotations) (download)
Wed Jul 29 15:31:09 2009 UTC (14 years, 9 months ago) by persson
File size: 13391 byte(s)
* ASIO fixes: avoid initializing the device twice, avoid throwing
  exception when getting parameters from a disconnected device
* Windows: add the installation directory to the DLL search path when
  loading an editor plugin (solves problems with VST and gigedit on
  systems with other GTK versions installed)
* fixed minor memory leak in ALSA MIDI driver

1 schoenebeck 201 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1715 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7 schoenebeck 201 * *
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 schoenebeck 226 #define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
28    
29 schoenebeck 201 namespace LinuxSampler {
30    
31 schoenebeck 221 // *************** ParameterName ***************
32     // *
33    
34 schoenebeck 880 MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::ParameterName(MidiInputPort* pPort) throw (Exception) : MidiInputPort::ParameterName(pPort, "Port " + ToString(pPort->GetPortNumber())) {
35 schoenebeck 221 OnSetValue(ValueAsString()); // initialize port name
36 schoenebeck 201 }
37    
38 schoenebeck 880 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::OnSetValue(String s) throw (Exception) {
39     if (s.size() > 16) throw Exception("Name too long for ALSA MIDI input port (max. 16 characters)");
40 schoenebeck 221 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 schoenebeck 201 }
47    
48 schoenebeck 221
49    
50     // *************** ParameterAlsaSeqBindings ***************
51     // *
52    
53    
54     MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::ParameterAlsaSeqBindings(MidiInputPortAlsa* pPort) : DeviceRuntimeParameterStrings( std::vector<String>() ) {
55     this->pPort = pPort;
56 schoenebeck 201 }
57    
58 schoenebeck 221 String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Description() {
59     return "Bindings to other Alsa sequencer clients";
60 schoenebeck 201 }
61 schoenebeck 221 bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Fix() {
62     return false;
63     }
64 schoenebeck 201
65 schoenebeck 221 std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::PossibilitiesAsString() {
66 schoenebeck 226 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 schoenebeck 201 }
87    
88 schoenebeck 880 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::OnSetValue(std::vector<String> vS) throw (Exception) {
89 persson 1951 pPort->UnsubscribeAll();
90 schoenebeck 1344
91 schoenebeck 221 std::vector<String>::iterator iter = vS.begin();
92     for (; iter != vS.end(); iter++) pPort->ConnectToAlsaMidiSource((*iter).c_str());
93 schoenebeck 201 }
94    
95 schoenebeck 221
96    
97 schoenebeck 476 // *************** ParameterAlsaSeqId ***************
98     // *
99    
100     MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::ParameterAlsaSeqId(MidiInputPortAlsa* pPort)
101     : DeviceRuntimeParameterString(ToString(pPort->pDevice->hAlsaSeqClient) + ":" + ToString(pPort->portNumber)) {
102     }
103    
104     String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::Description() {
105     return "ALSA Sequencer ID";
106     }
107    
108     bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::Fix() {
109     return true;
110     }
111    
112     std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::PossibilitiesAsString() {
113     return std::vector<String>(); // nothing
114     }
115    
116     void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqId::OnSetValue(String s) {
117     // not possible as parameter is 'fix'
118     }
119    
120    
121    
122 schoenebeck 221 // *************** MidiInputPortAlsa ***************
123     // *
124    
125     MidiInputDeviceAlsa::MidiInputPortAlsa::MidiInputPortAlsa(MidiInputDeviceAlsa* pDevice) throw (MidiInputException) : MidiInputPort(pDevice, -1) {
126     this->pDevice = pDevice;
127    
128     // create Alsa sequencer port
129     int alsaPort = snd_seq_create_simple_port(pDevice->hAlsaSeq, "unnamed port",
130     SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
131     SND_SEQ_PORT_TYPE_APPLICATION);
132     if (alsaPort < 0) throw MidiInputException("Error creating sequencer port");
133     this->portNumber = alsaPort;
134    
135 persson 1248 delete Parameters["NAME"];
136 schoenebeck 221 Parameters["NAME"] = new ParameterName(this);
137     Parameters["ALSA_SEQ_BINDINGS"] = new ParameterAlsaSeqBindings(this);
138 schoenebeck 476 Parameters["ALSA_SEQ_ID"] = new ParameterAlsaSeqId(this);
139 schoenebeck 201 }
140    
141 schoenebeck 221 MidiInputDeviceAlsa::MidiInputPortAlsa::~MidiInputPortAlsa() {
142 persson 1951 UnsubscribeAll();
143     snd_seq_delete_simple_port(pDevice->hAlsaSeq, portNumber);
144 schoenebeck 201 }
145    
146     /**
147 schoenebeck 221 * Connects this Alsa midi input device with an Alsa MIDI source.
148     *
149     * @param Client - Alsa sequencer client and port ID of a MIDI source
150     * (e.g. "64:0")
151     * @throws MidiInputException if connection cannot be established
152     */
153 schoenebeck 201 void MidiInputDeviceAlsa::MidiInputPortAlsa::ConnectToAlsaMidiSource(const char* MidiSource) {
154     snd_seq_addr_t sender, dest;
155     snd_seq_port_subscribe_t* subs;
156     int hExtClient, hExtPort;
157    
158     sscanf(MidiSource, "%d:%d", &hExtClient, &hExtPort);
159     sender.client = (char) hExtClient;
160     sender.port = (char) hExtPort;
161     dest.client = (char) pDevice->hAlsaSeqClient;
162     dest.port = (char) portNumber;
163 iliev 1296 snd_seq_port_subscribe_malloc(&subs);
164 schoenebeck 201 snd_seq_port_subscribe_set_sender(subs, &sender);
165     snd_seq_port_subscribe_set_dest(subs, &dest);
166     snd_seq_port_subscribe_set_queue(subs, 1);
167     snd_seq_port_subscribe_set_time_update(subs, 1);
168     snd_seq_port_subscribe_set_time_real(subs, 1);
169 iliev 1296 if (snd_seq_subscribe_port(pDevice->hAlsaSeq, subs) < 0) {
170     snd_seq_port_subscribe_free(subs);
171 schoenebeck 201 throw MidiInputException(String("Unable to connect to Alsa seq client \'") + MidiSource + "\' (" + snd_strerror(errno) + ")");
172 iliev 1296 }
173    
174     subscriptions.push_back(subs);
175 schoenebeck 201 }
176    
177 persson 1951 void MidiInputDeviceAlsa::MidiInputPortAlsa::UnsubscribeAll() {
178     for (std::vector<snd_seq_port_subscribe_t*>::iterator it = subscriptions.begin();
179     it != subscriptions.end(); it++) {
180     if (snd_seq_unsubscribe_port(pDevice->hAlsaSeq, *it)) {
181     dmsg(1,("MidiInputPortAlsa::UnsubscribeAll: Can't unsubscribe port connection!.\n"));
182     }
183     snd_seq_port_subscribe_free(*it);
184     }
185     subscriptions.clear();
186     }
187 schoenebeck 221
188     // *************** MidiInputDeviceAlsa ***************
189     // *
190    
191 schoenebeck 551 MidiInputDeviceAlsa::MidiInputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler), Thread(true, true, 1, -1) {
192 schoenebeck 221 if (snd_seq_open(&hAlsaSeq, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
193     throw MidiInputException("Error opening ALSA sequencer");
194     }
195     this->hAlsaSeqClient = snd_seq_client_id(hAlsaSeq);
196     snd_seq_set_client_name(hAlsaSeq, "LinuxSampler");
197     AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
198     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
199     Listen();
200     }
201     }
202    
203     MidiInputDeviceAlsa::~MidiInputDeviceAlsa() {
204 persson 1248 // free the midi ports (we can't let the base class do this,
205     // as the MidiInputPortAlsa destructors need access to
206     // hAlsaSeq)
207     for (std::map<int,MidiInputPort*>::iterator iter = Ports.begin(); iter != Ports.end() ; iter++) {
208     delete static_cast<MidiInputPortAlsa*>(iter->second);
209     }
210     Ports.clear();
211    
212     snd_seq_close(hAlsaSeq);
213 schoenebeck 221 }
214    
215     MidiInputDeviceAlsa::MidiInputPortAlsa* MidiInputDeviceAlsa::CreateMidiPort() {
216     return new MidiInputPortAlsa(this);
217     }
218    
219     String MidiInputDeviceAlsa::Name() {
220     return "ALSA";
221     }
222    
223     String MidiInputDeviceAlsa::Driver() {
224     return Name();
225     }
226    
227     void MidiInputDeviceAlsa::Listen() {
228     StartThread();
229     }
230    
231     void MidiInputDeviceAlsa::StopListen() {
232     StopThread();
233     }
234    
235 schoenebeck 201 String MidiInputDeviceAlsa::Description() {
236     return "Advanced Linux Sound Architecture";
237     }
238    
239     String MidiInputDeviceAlsa::Version() {
240 persson 1951 String s = "$Revision: 1.23 $";
241 schoenebeck 201 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
242     }
243    
244     int MidiInputDeviceAlsa::Main() {
245     int npfd;
246     struct pollfd* pfd;
247     snd_seq_event_t* ev;
248    
249     npfd = snd_seq_poll_descriptors_count(hAlsaSeq, POLLIN);
250     pfd = (struct pollfd*) alloca(npfd * sizeof(struct pollfd));
251     snd_seq_poll_descriptors(hAlsaSeq, pfd, npfd, POLLIN);
252     while (true) {
253     if (poll(pfd, npfd, 100000) > 0) {
254     do {
255     snd_seq_event_input(hAlsaSeq, &ev);
256 schoenebeck 221 int port = (int) ev->dest.port;
257     MidiInputPort* pMidiInputPort = Ports[port];
258 schoenebeck 201
259     switch (ev->type) {
260     case SND_SEQ_EVENT_CONTROLLER:
261 schoenebeck 947 if (ev->data.control.param == 0)
262     pMidiInputPort->DispatchBankSelectMsb(ev->data.control.value, ev->data.control.channel);
263     else if (ev->data.control.param == 32)
264     pMidiInputPort->DispatchBankSelectLsb(ev->data.control.value, ev->data.control.channel);
265 schoenebeck 1715 pMidiInputPort->DispatchControlChange(ev->data.control.param, ev->data.control.value, ev->data.control.channel);
266 schoenebeck 201 break;
267    
268 persson 903 case SND_SEQ_EVENT_CHANPRESS:
269     pMidiInputPort->DispatchControlChange(128, ev->data.control.value, ev->data.control.channel);
270     break;
271    
272 schoenebeck 201 case SND_SEQ_EVENT_PITCHBEND:
273     pMidiInputPort->DispatchPitchbend(ev->data.control.value, ev->data.control.channel);
274     break;
275    
276     case SND_SEQ_EVENT_NOTEON:
277     if (ev->data.note.velocity != 0) {
278     pMidiInputPort->DispatchNoteOn(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
279     }
280     else {
281     pMidiInputPort->DispatchNoteOff(ev->data.note.note, 0, ev->data.control.channel);
282     }
283     break;
284    
285     case SND_SEQ_EVENT_NOTEOFF:
286     pMidiInputPort->DispatchNoteOff(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
287     break;
288 schoenebeck 244
289     case SND_SEQ_EVENT_SYSEX:
290     pMidiInputPort->DispatchSysex(ev->data.ext.ptr, ev->data.ext.len);
291     break;
292 schoenebeck 551
293     case SND_SEQ_EVENT_PGMCHANGE:
294     pMidiInputPort->DispatchProgramChange(ev->data.control.value, ev->data.control.channel);
295     break;
296 schoenebeck 201 }
297     snd_seq_free_event(ev);
298     } while (snd_seq_event_input_pending(hAlsaSeq, 0) > 0);
299     }
300     }
301 schoenebeck 1344 // just to avoid a compiler warning
302     return EXIT_FAILURE;
303 schoenebeck 201 }
304    
305     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC