/[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 226 - (hide 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 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 REGISTER_MIDI_INPUT_DRIVER(MidiInputDeviceAlsa);
31 schoenebeck 201
32 schoenebeck 221 /* Common parameters */
33     REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDeviceAlsa, ParameterActive);
34     REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDeviceAlsa, ParameterPorts);
35 schoenebeck 201
36    
37 schoenebeck 221
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 schoenebeck 201 }
44    
45 schoenebeck 221 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 schoenebeck 201 }
54    
55 schoenebeck 221
56    
57     // *************** ParameterAlsaSeqBindings ***************
58     // *
59    
60    
61     MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::ParameterAlsaSeqBindings(MidiInputPortAlsa* pPort) : DeviceRuntimeParameterStrings( std::vector<String>() ) {
62     this->pPort = pPort;
63 schoenebeck 201 }
64    
65 schoenebeck 221 String MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Description() {
66     return "Bindings to other Alsa sequencer clients";
67 schoenebeck 201 }
68 schoenebeck 221 bool MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::Fix() {
69     return false;
70     }
71 schoenebeck 201
72 schoenebeck 221 std::vector<String> MidiInputDeviceAlsa::MidiInputPortAlsa::ParameterAlsaSeqBindings::PossibilitiesAsString() {
73 schoenebeck 226 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 schoenebeck 201 }
94    
95 schoenebeck 221 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 schoenebeck 201 }
99    
100 schoenebeck 221
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 schoenebeck 201 }
118    
119 schoenebeck 221 MidiInputDeviceAlsa::MidiInputPortAlsa::~MidiInputPortAlsa() {
120     snd_seq_delete_simple_port(pDevice->hAlsaSeq, portNumber);
121 schoenebeck 201 }
122    
123     /**
124 schoenebeck 221 * 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 schoenebeck 201 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 schoenebeck 221
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 schoenebeck 201 String MidiInputDeviceAlsa::Description() {
192     return "Advanced Linux Sound Architecture";
193     }
194    
195     String MidiInputDeviceAlsa::Version() {
196 schoenebeck 226 String s = "$Revision: 1.10 $";
197 schoenebeck 201 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 schoenebeck 221 int port = (int) ev->dest.port;
213     MidiInputPort* pMidiInputPort = Ports[port];
214 schoenebeck 201
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