/[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 2428 - (show annotations) (download)
Sat Mar 2 13:54:22 2013 UTC (8 years ago) by schoenebeck
File size: 12351 byte(s)
* Reverted yesterday's MME driver change for now (requires some
  additional code in RTMath for being able to work correctly).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2012 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_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR 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_PTR)win32_midiin_callback, (DWORD_PTR)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_PTR dwParam1, DWORD_PTR 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 //FIXME: passing timeStamp this way here does not work, since the DispatchRaw() expects it to be in period position, not miliseconds, requires additional code in RTMath to be able to transform the value for this purpose here
251 //int32_t timeStamp = dwParam2;
252 //DispatchRaw(data, timeStamp);
253 DispatchRaw(data);
254 break;
255 }
256
257 case MIM_LONGDATA:
258 if(!ExitFlag) {
259 LPMIDIHDR lpMIDIHeader = (LPMIDIHDR)dwParam1;
260 DataPtr = (unsigned char *)(lpMIDIHeader->lpData);
261 if(lpMIDIHeader->dwBytesRecorded == 0) break;
262
263 if(FirstSysExBlock) {
264 SysExOffset = 0;
265 FirstSysExBlock = false;
266 }
267
268 if( DataPtr[lpMIDIHeader->dwBytesRecorded - 1] == 0xF7) {
269 SysExMsgComplete = true;
270 FirstSysExBlock = true;
271 }
272 else {
273 SysExMsgComplete = false;
274 }
275
276 if(SysExOffset + lpMIDIHeader->dwBytesRecorded <= MME_MAX_SYSEX_BUF_SIZE) {
277 memcpy(&SysExBuf[SysExOffset], DataPtr, lpMIDIHeader->dwBytesRecorded);
278 SysExOffset += lpMIDIHeader->dwBytesRecorded;
279 }
280
281 if(SysExMsgComplete) DispatchSysex(SysExBuf, SysExOffset);
282
283 /* Queue the MIDIHDR for more input, only if ExitFlag was not set otherwise we risk an infinite loop
284 because when we call midiInReset() below, Windows will send a final MIM_LONGDATA message to that callback.
285 */
286 midiInAddBuffer(MidiInHandle, lpMIDIHeader, sizeof(MIDIHDR));
287 }
288 break;
289 }
290
291 }
292
293
294
295
296 // *************** MidiInputDeviceMme ***************
297 // *
298
299 MidiInputDeviceMme::MidiInputDeviceMme(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler) {
300 AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
301 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
302 Listen();
303 }
304 }
305
306 MidiInputDeviceMme::~MidiInputDeviceMme() {
307 // free the midi ports (we can't let the base class do this,
308 // as the MidiInputPortMme destructors need access to
309 // hAlsaSeq)
310 for (std::map<int,MidiInputPort*>::iterator iter = Ports.begin(); iter != Ports.end() ; iter++) {
311 delete static_cast<MidiInputPortMme*>(iter->second);
312 }
313 Ports.clear();
314 }
315
316 MidiInputDeviceMme::MidiInputPortMme* MidiInputDeviceMme::CreateMidiPort() {
317 return new MidiInputPortMme(this);
318 }
319
320 String MidiInputDeviceMme::Name() {
321 return "MME";
322 }
323
324 String MidiInputDeviceMme::Driver() {
325 return Name();
326 }
327
328 void MidiInputDeviceMme::Listen() {
329 //TODO: ...
330 }
331
332 void MidiInputDeviceMme::StopListen() {
333 //TODO: ...
334 }
335
336 String MidiInputDeviceMme::Description() {
337 return "MultiMedia Extensions";
338 }
339
340 String MidiInputDeviceMme::Version() {
341 String s = "$Revision: 1.5 $";
342 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
343 }
344
345
346
347 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC