/[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 226 - (show annotations) (download)
Wed Aug 25 22:00:33 2004 UTC (19 years, 7 months ago) by schoenebeck
File size: 10756 byte(s)
* ALSA MIDI driver: create one MIDI port by default, implemented parameter
  info for parameter 'ALSA_SEQ_BINDINGS'
* ALSA audio driver: implemented parameter info for driver parameters
  'FRAGMENTS' and 'FRAGMENTSIZE'
* JACK audio driver: fixed creation of channels on device creation, channel
  parameter 'NAME' now actually updates the respective JACK port name,
  implemented channel parameter 'JACK_BINDINGS' (as well as its parameter
  info)
* src/network/lscpserver.cpp: fixed commands
  "GET MIDI_INPUT_DRIVER_PARAMETER INFO" and
  "GET AUDIO_OUTPUT_DRIVER_PARAMETER  INFO", fixed backward compatibility
  for "SET AUDIO_OUTPUT_TYPE" and "SET MIDI_INPUT_TYPE" commands
* src/networ/lscp.y: added comma character (',') to symbol 'char'
* src/drivers/DeviceParameter.cpp: fixed methods RangeMin(), RangeMax() in
  class DeviceCreationParameterInt which returned wrong values

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 REGISTER_MIDI_INPUT_DRIVER(MidiInputDeviceAlsa);
31
32 /* Common parameters */
33 REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDeviceAlsa, ParameterActive);
34 REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDeviceAlsa, ParameterPorts);
35
36
37
38 // *************** ParameterName ***************
39 // *
40
41 MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::ParameterName(MidiInputPort* pPort) throw (LinuxSamplerException) : MidiInputPort::ParameterName(pPort, "Port " + ToString(pPort->GetPortNumber())) {
42 OnSetValue(ValueAsString()); // initialize port name
43 }
44
45 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {
46 if (s.size() > 16) throw LinuxSamplerException("Name too long for ALSA MIDI input port (max. 16 characters)");
47 snd_seq_port_info_t* hInfo;
48 snd_seq_port_info_malloc(&hInfo);
49 snd_seq_get_port_info(((MidiInputDeviceAlsa*)pPort->GetDevice())->hAlsaSeq, pPort->GetPortNumber(), hInfo);
50 snd_seq_port_info_set_name(hInfo, s.c_str());
51 snd_seq_set_port_info(((MidiInputDeviceAlsa*)pPort->GetDevice())->hAlsaSeq, pPort->GetPortNumber(), hInfo);
52 snd_seq_port_info_free(hInfo);
53 }
54
55
56
57 // *************** ParameterAlsaSeqBindings ***************
58 // *
59
60
61 MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::ParameterAlsaSeqBindings(MidiInputPortAlsa* pPort) : DeviceRuntimeParameterStrings( std::vector<String>() ) {
62 this->pPort = pPort;
63 }
64
65 String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Description() {
66 return "Bindings to other Alsa sequencer clients";
67 }
68 bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Fix() {
69 return false;
70 }
71
72 std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::PossibilitiesAsString() {
73 std::vector<String> res;
74 snd_seq_client_info_t* cinfo;
75 snd_seq_port_info_t* pinfo;
76
77 snd_seq_client_info_alloca(&cinfo);
78 snd_seq_port_info_alloca(&pinfo);
79 snd_seq_client_info_set_client(cinfo, -1);
80 while (snd_seq_query_next_client(pPort->pDevice->hAlsaSeq, cinfo) >= 0) {
81 snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
82 snd_seq_port_info_set_port(pinfo, -1);
83 while (snd_seq_query_next_port(pPort->pDevice->hAlsaSeq, pinfo) >= 0) {
84 if (perm_ok(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ)) {
85 String seq_id = ToString(snd_seq_client_info_get_client(cinfo)) + ":" +
86 ToString(snd_seq_port_info_get_port(pinfo));
87 res.push_back(seq_id);
88 }
89 }
90 }
91
92 return res;
93 }
94
95 void MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::OnSetValue(std::vector<String> vS) throw (LinuxSamplerException) {
96 std::vector<String>::iterator iter = vS.begin();
97 for (; iter != vS.end(); iter++) pPort->ConnectToAlsaMidiSource((*iter).c_str());
98 }
99
100
101
102 // *************** MidiInputPortAlsa ***************
103 // *
104
105 MidiInputDeviceAlsa::MidiInputPortAlsa::MidiInputPortAlsa(MidiInputDeviceAlsa* pDevice) throw (MidiInputException) : MidiInputPort(pDevice, -1) {
106 this->pDevice = pDevice;
107
108 // create Alsa sequencer port
109 int alsaPort = snd_seq_create_simple_port(pDevice->hAlsaSeq, "unnamed port",
110 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
111 SND_SEQ_PORT_TYPE_APPLICATION);
112 if (alsaPort < 0) throw MidiInputException("Error creating sequencer port");
113 this->portNumber = alsaPort;
114
115 Parameters["NAME"] = new ParameterName(this);
116 Parameters["ALSA_SEQ_BINDINGS"] = new ParameterAlsaSeqBindings(this);
117 }
118
119 MidiInputDeviceAlsa::MidiInputPortAlsa::~MidiInputPortAlsa() {
120 snd_seq_delete_simple_port(pDevice->hAlsaSeq, portNumber);
121 }
122
123 /**
124 * Connects this Alsa midi input device with an Alsa MIDI source.
125 *
126 * @param Client - Alsa sequencer client and port ID of a MIDI source
127 * (e.g. "64:0")
128 * @throws MidiInputException if connection cannot be established
129 */
130 void MidiInputDeviceAlsa::MidiInputPortAlsa::ConnectToAlsaMidiSource(const char* MidiSource) {
131 snd_seq_addr_t sender, dest;
132 snd_seq_port_subscribe_t* subs;
133 int hExtClient, hExtPort;
134
135 sscanf(MidiSource, "%d:%d", &hExtClient, &hExtPort);
136 sender.client = (char) hExtClient;
137 sender.port = (char) hExtPort;
138 dest.client = (char) pDevice->hAlsaSeqClient;
139 dest.port = (char) portNumber;
140 snd_seq_port_subscribe_alloca(&subs);
141 snd_seq_port_subscribe_set_sender(subs, &sender);
142 snd_seq_port_subscribe_set_dest(subs, &dest);
143 snd_seq_port_subscribe_set_queue(subs, 1);
144 snd_seq_port_subscribe_set_time_update(subs, 1);
145 snd_seq_port_subscribe_set_time_real(subs, 1);
146 if (snd_seq_subscribe_port(pDevice->hAlsaSeq, subs) < 0)
147 throw MidiInputException(String("Unable to connect to Alsa seq client \'") + MidiSource + "\' (" + snd_strerror(errno) + ")");
148 }
149
150
151
152 // *************** MidiInputDeviceAlsa ***************
153 // *
154
155 MidiInputDeviceAlsa::MidiInputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : MidiInputDevice(Parameters), Thread(true, 1, -1) {
156 if (snd_seq_open(&hAlsaSeq, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
157 throw MidiInputException("Error opening ALSA sequencer");
158 }
159 this->hAlsaSeqClient = snd_seq_client_id(hAlsaSeq);
160 snd_seq_set_client_name(hAlsaSeq, "LinuxSampler");
161 AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
162 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
163 Listen();
164 }
165 }
166
167 MidiInputDeviceAlsa::~MidiInputDeviceAlsa() {
168 snd_seq_close(hAlsaSeq);
169 }
170
171 MidiInputDeviceAlsa::MidiInputPortAlsa* MidiInputDeviceAlsa::CreateMidiPort() {
172 return new MidiInputPortAlsa(this);
173 }
174
175 String MidiInputDeviceAlsa::Name() {
176 return "ALSA";
177 }
178
179 String MidiInputDeviceAlsa::Driver() {
180 return Name();
181 }
182
183 void MidiInputDeviceAlsa::Listen() {
184 StartThread();
185 }
186
187 void MidiInputDeviceAlsa::StopListen() {
188 StopThread();
189 }
190
191 String MidiInputDeviceAlsa::Description() {
192 return "Advanced Linux Sound Architecture";
193 }
194
195 String MidiInputDeviceAlsa::Version() {
196 String s = "$Revision: 1.10 $";
197 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
198 }
199
200 int MidiInputDeviceAlsa::Main() {
201 int npfd;
202 struct pollfd* pfd;
203 snd_seq_event_t* ev;
204
205 npfd = snd_seq_poll_descriptors_count(hAlsaSeq, POLLIN);
206 pfd = (struct pollfd*) alloca(npfd * sizeof(struct pollfd));
207 snd_seq_poll_descriptors(hAlsaSeq, pfd, npfd, POLLIN);
208 while (true) {
209 if (poll(pfd, npfd, 100000) > 0) {
210 do {
211 snd_seq_event_input(hAlsaSeq, &ev);
212 int port = (int) ev->dest.port;
213 MidiInputPort* pMidiInputPort = Ports[port];
214
215 switch (ev->type) {
216 case SND_SEQ_EVENT_CONTROLLER:
217 pMidiInputPort->DispatchControlChange(ev->data.control.param, ev->data.control.value, ev->data.control.channel);
218 break;
219
220 case SND_SEQ_EVENT_PITCHBEND:
221 // fprintf(stderr, "Pitchbender event on Channel %2d: %5d \n",
222 // ev->data.control.channel, ev->data.control.value);
223 pMidiInputPort->DispatchPitchbend(ev->data.control.value, ev->data.control.channel);
224 break;
225
226 case SND_SEQ_EVENT_NOTEON:
227 if (ev->data.note.velocity != 0) {
228 pMidiInputPort->DispatchNoteOn(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
229 }
230 else {
231 pMidiInputPort->DispatchNoteOff(ev->data.note.note, 0, ev->data.control.channel);
232 }
233 break;
234
235 case SND_SEQ_EVENT_NOTEOFF:
236 pMidiInputPort->DispatchNoteOff(ev->data.note.note, ev->data.note.velocity, ev->data.control.channel);
237 break;
238 }
239 snd_seq_free_event(ev);
240 } while (snd_seq_event_input_pending(hAlsaSeq, 0) > 0);
241 }
242 }
243 }
244
245 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC