/[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 476 - (hide annotations) (download)
Fri Mar 18 18:16:27 2005 UTC (19 years, 1 month ago) by schoenebeck
File size: 11691 byte(s)
* ALSA MIDI driver: added MIDI port parameter 'ALSA_SEQ_ID' which reflects
  the ALSA sequencer ID of a port (read only)

1 schoenebeck 201 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 476 * Copyright (C) 2005 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     MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::ParameterName(MidiInputPort* pPort) throw (LinuxSamplerException) : MidiInputPort::ParameterName(pPort, "Port " + ToString(pPort->GetPortNumber())) {
35     OnSetValue(ValueAsString()); // initialize port name
36 schoenebeck 201 }
37    
38 schoenebeck 221 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 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 221 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 schoenebeck 201 }
92    
93 schoenebeck 221
94    
95 schoenebeck 476 // *************** 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 schoenebeck 221 // *************** 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 schoenebeck 476 Parameters["ALSA_SEQ_ID"] = new ParameterAlsaSeqId(this);
136 schoenebeck 201 }
137    
138 schoenebeck 221 MidiInputDeviceAlsa::MidiInputPortAlsa::~MidiInputPortAlsa() {
139     snd_seq_delete_simple_port(pDevice->hAlsaSeq, portNumber);
140 schoenebeck 201 }
141    
142     /**
143 schoenebeck 221 * 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 schoenebeck 201 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 schoenebeck 221
170    
171     // *************** MidiInputDeviceAlsa ***************
172     // *
173    
174 schoenebeck 392 MidiInputDeviceAlsa::MidiInputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : MidiInputDevice(Parameters), Thread(true, true, 1, -1) {
175 schoenebeck 221 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 schoenebeck 201 String MidiInputDeviceAlsa::Description() {
211     return "Advanced Linux Sound Architecture";
212     }
213    
214     String MidiInputDeviceAlsa::Version() {
215 schoenebeck 476 String s = "$Revision: 1.14 $";
216 schoenebeck 201 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 schoenebeck 221 int port = (int) ev->dest.port;
232     MidiInputPort* pMidiInputPort = Ports[port];
233 schoenebeck 201
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     // fprintf(stderr, "Pitchbender event on Channel %2d: %5d \n",
241     // ev->data.control.channel, ev->data.control.value);
242     pMidiInputPort->DispatchPitchbend(ev->data.control.value, ev->data.control.channel);
243     break;
244    
245     case SND_SEQ_EVENT_NOTEON:
246     if (ev->data.note.velocity != 0) {
247     pMidiInputPort->DispatchNoteOn(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
248     }
249     else {
250     pMidiInputPort->DispatchNoteOff(ev->data.note.note, 0, ev->data.control.channel);
251     }
252     break;
253    
254     case SND_SEQ_EVENT_NOTEOFF:
255     pMidiInputPort->DispatchNoteOff(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
256     break;
257 schoenebeck 244
258     case SND_SEQ_EVENT_SYSEX:
259     pMidiInputPort->DispatchSysex(ev->data.ext.ptr, ev->data.ext.len);
260     break;
261 schoenebeck 201 }
262     snd_seq_free_event(ev);
263     } while (snd_seq_event_input_pending(hAlsaSeq, 0) > 0);
264     }
265     }
266     }
267    
268     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC