/[svn]/linuxsampler/trunk/src/drivers/midi/MidiInputDeviceMme.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/midi/MidiInputDeviceMme.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1715 - (show annotations) (download)
Tue Mar 11 15:20:46 2008 UTC (16 years ago) by schoenebeck
File size: 13422 byte(s)
* dispatch bank select as ordinary CC as well, the user might seriously
  want to (mis)use it for some purpose ("fixed" in all current MIDI
  input drivers: ALSA, CoreMIDI, JACK, MidiShare, MME)
* minor fix: only mark FX sends as being modified if really the
  respective FX send MIDI controller was used

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7 * *
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 "MidiInputDeviceMme.h"
25 #include "MidiInputDeviceFactory.h"
26
27
28
29
30 namespace LinuxSampler {
31
32 void CALLBACK MidiInputDeviceMme::MidiInputPortMme::win32_midiin_callback(HMIDIIN handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
33 MidiInputDeviceMme::MidiInputPortMme* p = (MidiInputDeviceMme::MidiInputPortMme*)dwInstance;
34 p->MmeCallbackDispatcher(handle, uMsg, dwParam1, dwParam2);
35 }
36
37
38
39 // *************** ParameterPorts ***************
40 // *
41
42 // *************** ParameterPorts ***************
43 // *
44
45 MidiInputDeviceMme::ParameterPorts::ParameterPorts() : DeviceCreationParameterInt() {
46 InitWithDefault();
47 }
48
49 MidiInputDeviceMme::ParameterPorts::ParameterPorts(String val) : DeviceCreationParameterInt(val) {
50 }
51
52 String MidiInputDeviceMme::ParameterPorts::Description() {
53 return "Number of ports";
54 }
55
56 bool MidiInputDeviceMme::ParameterPorts::Fix() {
57 return true;
58 }
59
60 bool MidiInputDeviceMme::ParameterPorts::Mandatory() {
61 return false;
62 }
63
64 std::map<String,DeviceCreationParameter*> MidiInputDeviceMme::ParameterPorts::DependsAsParameters() {
65 return std::map<String,DeviceCreationParameter*>();
66 }
67
68 // the MME driver supports only one port so to manage multiple MME MIDI ports the user just creates several MME drivers and connects each one to the desired MME port
69 optional<int> MidiInputDeviceMme::ParameterPorts::DefaultAsInt(std::map<String,String> Parameters) {
70 return 1;
71 }
72
73 optional<int> MidiInputDeviceMme::ParameterPorts::RangeMinAsInt(std::map<String,String> Parameters) {
74 return 1;
75 }
76
77 optional<int> MidiInputDeviceMme::ParameterPorts::RangeMaxAsInt(std::map<String,String> Parameters) {
78 return 1;
79 }
80
81 std::vector<int> MidiInputDeviceMme::ParameterPorts::PossibilitiesAsInt(std::map<String,String> Parameters) {
82 return std::vector<int>();
83 }
84
85 void MidiInputDeviceMme::ParameterPorts::OnSetValue(int i) throw (Exception) {
86 if (i != 1) throw Exception("MME only supports one MIDI port per device");
87 }
88
89 String MidiInputDeviceMme::ParameterPorts::Name() {
90 return "PORTS";
91 }
92
93 // the MME driver supports only one port so to manage multiple MME MIDI ports the user just creates several MME drivers and connects each one to the desired MME port
94
95
96
97 // *************** ParameterPort ***************
98 // *
99
100 MidiInputDeviceMme::MidiInputPortMme::ParameterPort::ParameterPort(MidiInputPortMme* pPort)
101 : DeviceRuntimeParameterString("") {
102 this->pPort = pPort;
103 }
104
105 String MidiInputDeviceMme::MidiInputPortMme::ParameterPort::Description() {
106 return "MME Destination MIDI Port";
107 }
108
109 bool MidiInputDeviceMme::MidiInputPortMme::ParameterPort::Fix() {
110 return false;
111 }
112
113 std::vector<String> MidiInputDeviceMme::MidiInputPortMme::ParameterPort::PossibilitiesAsString() {
114 // returns a list of the available MME Input MIDI ports you can connect to
115 std::vector<String> ports;
116 MIDIINCAPS midiincaps;
117
118 int NumDevs = midiInGetNumDevs();
119
120 for(int i=0;i<NumDevs;i++) {
121 int res = midiInGetDevCaps(i, &midiincaps, sizeof(MIDIINCAPS));
122 if(res == MMSYSERR_NOERROR) {
123 ports.push_back( (String)midiincaps.szPname);
124 }
125 }
126
127 return ports;
128 }
129
130 void MidiInputDeviceMme::MidiInputPortMme::ParameterPort::OnSetValue(String s) {
131 pPort->ConnectToMmeMidiSource(s.c_str());
132 }
133
134
135
136 // *************** MidiInputPortMme ***************
137 // *
138
139 MidiInputDeviceMme::MidiInputPortMme::MidiInputPortMme(MidiInputDeviceMme* pDevice) throw (MidiInputException)
140 : MidiInputPort(pDevice, ((DeviceCreationParameterInt*)pDevice->Parameters["PORTS"])->ValueAsInt() - 1)
141 {
142 this->pDevice = pDevice;
143 MidiInOpened = false;
144 SysExBuf = new char[MME_MAX_SYSEX_BUF_SIZE];
145 TmpSysExBuf = new char[MME_MAX_SYSEX_BUF_SIZE];
146 ExitFlag = false;
147 FirstSysExBlock = true;
148 SysExMsgComplete = false;
149 dmsg(3,("created MME port %d\n", this->portNumber));
150 Parameters["PORT"] = new ParameterPort(this);
151 }
152
153 MidiInputDeviceMme::MidiInputPortMme::~MidiInputPortMme() {
154 delete TmpSysExBuf;
155 delete SysExBuf;
156 }
157
158
159 /***
160 * Closes the MME MIDI Input port in a safe way
161 */
162 void MidiInputDeviceMme::MidiInputPortMme::CloseMmeMidiPort(void) {
163 int res;
164 if (MidiInOpened == true) {
165 ExitFlag = true;
166 midiInReset(MidiInHandle);
167 while ((res = midiInClose(MidiInHandle)) == MIDIERR_STILLPLAYING) Sleep(100);
168 midiInUnprepareHeader(MidiInHandle, &midiHdr, sizeof(MIDIHDR));
169 MidiInOpened = false;
170 }
171 }
172
173 /**
174 * Connects the port with the MME Midi Input port
175 *
176 * @param Name of the MME Midi Input port e.g. "MAUDIO MIDI IN"
177 * @throws MidiInputException if connection cannot be established
178 */
179
180 void MidiInputDeviceMme::MidiInputPortMme::ConnectToMmeMidiSource(const char* MidiSource) {
181
182 // close the old MIDI Input port if it was already opened
183 CloseMmeMidiPort();
184
185 MIDIINCAPS midiincaps;
186 int NumDevs = midiInGetNumDevs();
187
188 int FoundMidiInDeviceId = -1;
189 for(int i=0;i<NumDevs;i++) {
190 int res = midiInGetDevCaps(i, &midiincaps, sizeof(MIDIINCAPS));
191 if(res == MMSYSERR_NOERROR) {
192 if(!strcmp(midiincaps.szPname, MidiSource)) {
193 FoundMidiInDeviceId = i;
194 break;
195 }
196 }
197 }
198
199 if(FoundMidiInDeviceId == -1) throw MidiInputException("MIDI port connect failed");
200
201 int res;
202 res = midiInOpen(&MidiInHandle, FoundMidiInDeviceId, (DWORD)win32_midiin_callback, (DWORD)this, CALLBACK_FUNCTION);
203 if(res != MMSYSERR_NOERROR) {
204 throw MidiInputException("MIDI port connect failed. midiInOpen error");
205 }
206
207 MidiInOpened = true;
208
209 /* Store pointer to our input buffer for System Exclusive messages in MIDIHDR */
210 midiHdr.lpData = &TmpSysExBuf[0];
211
212 /* Store its size in the MIDIHDR */
213 midiHdr.dwBufferLength = MME_MAX_SYSEX_BUF_SIZE;
214
215 /* Flags must be set to 0 */
216 midiHdr.dwFlags = 0;
217
218 /* Prepare the buffer and MIDIHDR */
219 res = midiInPrepareHeader(MidiInHandle, &midiHdr, sizeof(MIDIHDR));
220 if(res != MMSYSERR_NOERROR) {
221 CloseMmeMidiPort();
222 throw MidiInputException("MIDI port connect failed. midiInPrepareHeader error");
223 }
224
225 /* Queue MIDI input buffer */
226 res = midiInAddBuffer(MidiInHandle, &midiHdr, sizeof(MIDIHDR));
227 if(res != MMSYSERR_NOERROR) {
228 CloseMmeMidiPort();
229 throw MidiInputException("MIDI port connect failed. midiInAddBuffer error");
230 }
231
232
233 res = midiInStart(MidiInHandle);
234 if(res != MMSYSERR_NOERROR) {
235 CloseMmeMidiPort();
236 throw MidiInputException("MIDI port connect failed, midiInStart failed.");
237 }
238
239 }
240
241 void MidiInputDeviceMme::MidiInputPortMme::MmeCallbackDispatcher(HMIDIIN handle, UINT uMsg, DWORD dwParam1, DWORD dwParam2) {
242
243 unsigned char *DataPtr; // pointer to SysEx data
244 unsigned char *data; // pointer to standard MIDI messages which are not sysex data(max 3 bytes long)
245
246 data = (unsigned char *)&dwParam1;
247
248 switch(uMsg) {
249 case MIM_DATA:
250 switch(data[0] & 0xF0) { // status byte
251
252 case 0xB0:
253 if (data[1] == 0)
254 DispatchBankSelectMsb(data[2], data[0] & 0x0F);
255 else if (data[1] == 32)
256 DispatchBankSelectLsb(data[2], data[0] & 0x0F);
257 DispatchControlChange(data[1], data[2], data[0] & 0x0F);
258 break;
259
260 case 0xD0:
261 DispatchControlChange(128, data[1], data[0] & 0x0F);
262 break;
263
264 case 0xE0:
265 DispatchPitchbend(data[1], data[0] & 0x0F);
266 break;
267
268 case 0x90:
269 if (data[1] < 0x80) {
270 if (data[2] > 0){
271 DispatchNoteOn(data[1], data[2], data[0] & 0x0F);
272 }else{
273 DispatchNoteOff(data[1], data[2], data[0] & 0x0F);
274 }
275 }
276 break;
277
278 case 0x80:
279 if (data[1] < 0x80) {
280 DispatchNoteOff(data[1], data[2], data[0] & 0x0F);
281 }
282 break;
283
284 case 0xC0:
285 if (data[1] < 0x80) {
286 DispatchProgramChange(data[1], data[0] & 0x0F);
287 }
288 break;
289 }
290
291 break;
292
293 case MIM_LONGDATA:
294 if(!ExitFlag) {
295 LPMIDIHDR lpMIDIHeader = (LPMIDIHDR)dwParam1;
296 DataPtr = (unsigned char *)(lpMIDIHeader->lpData);
297 if(lpMIDIHeader->dwBytesRecorded == 0) break;
298
299 if(FirstSysExBlock) {
300 SysExOffset = 0;
301 FirstSysExBlock = false;
302 }
303
304 if( DataPtr[lpMIDIHeader->dwBytesRecorded - 1] == 0xF7) {
305 SysExMsgComplete = true;
306 FirstSysExBlock = true;
307 }
308 else {
309 SysExMsgComplete = false;
310 }
311
312 if(SysExOffset + lpMIDIHeader->dwBytesRecorded <= MME_MAX_SYSEX_BUF_SIZE) {
313 memcpy(&SysExBuf[SysExOffset], DataPtr, lpMIDIHeader->dwBytesRecorded);
314 SysExOffset += lpMIDIHeader->dwBytesRecorded;
315 }
316
317 if(SysExMsgComplete) DispatchSysex(SysExBuf, SysExOffset);
318
319 /* Queue the MIDIHDR for more input, only if ExitFlag was not set otherwise we risk an infinite loop
320 because when we call midiInReset() below, Windows will send a final MIM_LONGDATA message to that callback.
321 */
322 midiInAddBuffer(MidiInHandle, lpMIDIHeader, sizeof(MIDIHDR));
323 }
324 break;
325 }
326
327 }
328
329
330
331
332 // *************** MidiInputDeviceMme ***************
333 // *
334
335 MidiInputDeviceMme::MidiInputDeviceMme(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler) {
336 AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
337 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
338 Listen();
339 }
340 }
341
342 MidiInputDeviceMme::~MidiInputDeviceMme() {
343 // free the midi ports (we can't let the base class do this,
344 // as the MidiInputPortMme destructors need access to
345 // hAlsaSeq)
346 for (std::map<int,MidiInputPort*>::iterator iter = Ports.begin(); iter != Ports.end() ; iter++) {
347 delete static_cast<MidiInputPortMme*>(iter->second);
348 }
349 Ports.clear();
350 }
351
352 MidiInputDeviceMme::MidiInputPortMme* MidiInputDeviceMme::CreateMidiPort() {
353 return new MidiInputPortMme(this);
354 }
355
356 String MidiInputDeviceMme::Name() {
357 return "MME";
358 }
359
360 String MidiInputDeviceMme::Driver() {
361 return Name();
362 }
363
364 void MidiInputDeviceMme::Listen() {
365 //TODO: ...
366 }
367
368 void MidiInputDeviceMme::StopListen() {
369 //TODO: ...
370 }
371
372 String MidiInputDeviceMme::Description() {
373 return "MultiMedia Extensions";
374 }
375
376 String MidiInputDeviceMme::Version() {
377 String s = "$Revision: 1.3 $";
378 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
379 }
380
381
382
383 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC