/[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 551 - (hide 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 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 551 MidiInputDeviceAlsa::MidiInputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler), 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 551 String s = "$Revision: 1.15 $";
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     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 schoenebeck 244
256     case SND_SEQ_EVENT_SYSEX:
257     pMidiInputPort->DispatchSysex(ev->data.ext.ptr, ev->data.ext.len);
258     break;
259 schoenebeck 551
260     case SND_SEQ_EVENT_PGMCHANGE:
261     pMidiInputPort->DispatchProgramChange(ev->data.control.value, ev->data.control.channel);
262     break;
263 schoenebeck 201 }
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