/[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 289 - (hide annotations) (download)
Tue Oct 19 14:41:38 2004 UTC (19 years, 6 months ago) by schoenebeck
File size: 10693 byte(s)
* LinuxSampler was badly broken with last commit, fixed that
* using now James Klicman's proposol to fix the reported linker problem
* Mutex.cpp: try to force UNIX98 compatibility (if not already supported)
* Makefile.cvs: generate (and clean) all necessary autotools files

1 schoenebeck 201 /***************************************************************************
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 schoenebeck 226 #define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
27    
28 schoenebeck 201 namespace LinuxSampler {
29    
30 schoenebeck 221 // *************** 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 schoenebeck 201 }
36    
37 schoenebeck 221 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 schoenebeck 201 }
46    
47 schoenebeck 221
48    
49     // *************** ParameterAlsaSeqBindings ***************
50     // *
51    
52    
53     MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::ParameterAlsaSeqBindings(MidiInputPortAlsa* pPort) : DeviceRuntimeParameterStrings( std::vector<String>() ) {
54     this->pPort = pPort;
55 schoenebeck 201 }
56    
57 schoenebeck 221 String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Description() {
58     return "Bindings to other Alsa sequencer clients";
59 schoenebeck 201 }
60 schoenebeck 221 bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Fix() {
61     return false;
62     }
63 schoenebeck 201
64 schoenebeck 221 std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::PossibilitiesAsString() {
65 schoenebeck 226 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 schoenebeck 201 }
86    
87 schoenebeck 221 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 schoenebeck 201 }
91    
92 schoenebeck 221
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 schoenebeck 201 }
110    
111 schoenebeck 221 MidiInputDeviceAlsa::MidiInputPortAlsa::~MidiInputPortAlsa() {
112     snd_seq_delete_simple_port(pDevice->hAlsaSeq, portNumber);
113 schoenebeck 201 }
114    
115     /**
116 schoenebeck 221 * 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 schoenebeck 201 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 schoenebeck 221
143    
144     // *************** MidiInputDeviceAlsa ***************
145     // *
146    
147     MidiInputDeviceAlsa::MidiInputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : MidiInputDevice(Parameters), Thread(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 schoenebeck 201 String MidiInputDeviceAlsa::Description() {
184     return "Advanced Linux Sound Architecture";
185     }
186    
187     String MidiInputDeviceAlsa::Version() {
188 schoenebeck 289 String s = "$Revision: 1.12 $";
189 schoenebeck 201 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 schoenebeck 221 int port = (int) ev->dest.port;
205     MidiInputPort* pMidiInputPort = Ports[port];
206 schoenebeck 201
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 schoenebeck 244
231     case SND_SEQ_EVENT_SYSEX:
232     pMidiInputPort->DispatchSysex(ev->data.ext.ptr, ev->data.ext.len);
233     break;
234 schoenebeck 201 }
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