/[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 1889 - (show annotations) (download)
Sun Apr 26 12:19:00 2009 UTC (14 years, 11 months ago) by persson
File size: 11990 byte(s)
* fixed a memory management error which could cause a crash when a
  plugin was unloaded
* minor fixes in ASIO and MME drivers for win64

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

  ViewVC Help
Powered by ViewVC