/[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 2426 - (show annotations) (download)
Fri Mar 1 23:00:17 2013 UTC (7 years, 8 months ago) by schoenebeck
File size: 12097 byte(s)
* MIDI drivers: Implemented missing handling of MIDI "running status".
* MME driver: pass time stamps to the sampler.

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

  ViewVC Help
Powered by ViewVC