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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2426 - (hide annotations) (download)
Fri Mar 1 23:00:17 2013 UTC (11 years, 1 month 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 senoner 1485 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2311 * Copyright (C) 2005 - 2012 Christian Schoenebeck *
7 senoner 1485 * *
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 persson 2324 void CALLBACK MidiInputDeviceMme::MidiInputPortMme::win32_midiin_callback(HMIDIIN handle, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
33 senoner 1485 MidiInputDeviceMme::MidiInputPortMme* p = (MidiInputDeviceMme::MidiInputPortMme*)dwInstance;
34     p->MmeCallbackDispatcher(handle, uMsg, dwParam1, dwParam2);
35     }
36    
37    
38    
39 senoner 1500 // *************** ParameterPorts ***************
40     // *
41 senoner 1485
42 senoner 1500 // *************** 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 persson 1887
93 senoner 1500 // 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 persson 1887
97 senoner 1485 // *************** 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 persson 2311 delete[] TmpSysExBuf;
155     delete[] SysExBuf;
156 senoner 1485 }
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 persson 1889 res = midiInOpen(&MidiInHandle, FoundMidiInDeviceId, (DWORD_PTR)win32_midiin_callback, (DWORD_PTR)this, CALLBACK_FUNCTION);
203 senoner 1485 if(res != MMSYSERR_NOERROR) {
204     throw MidiInputException("MIDI port connect failed. midiInOpen error");
205     }
206 persson 1887
207 senoner 1485 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 persson 1887
225 senoner 1485 /* 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 persson 1887
233 senoner 1485 res = midiInStart(MidiInHandle);
234     if(res != MMSYSERR_NOERROR) {
235     CloseMmeMidiPort();
236     throw MidiInputException("MIDI port connect failed, midiInStart failed.");
237     }
238    
239     }
240 persson 1887
241 persson 2324 void MidiInputDeviceMme::MidiInputPortMme::MmeCallbackDispatcher(HMIDIIN handle, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
242 senoner 1485
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 schoenebeck 2426 case MIM_DATA: {
250     int32_t timeStamp = (dwParam2) ? *dwParam2 : 0;
251     DispatchRaw(data, timeStamp);
252 persson 1887 break;
253 schoenebeck 2426 }
254 senoner 1485
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 persson 1887 /* Queue the MIDIHDR for more input, only if ExitFlag was not set otherwise we risk an infinite loop
282 senoner 1485 because when we call midiInReset() below, Windows will send a final MIM_LONGDATA message to that callback.
283     */
284 persson 1887 midiInAddBuffer(MidiInHandle, lpMIDIHeader, sizeof(MIDIHDR));
285     }
286 senoner 1485 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 persson 1889 String s = "$Revision: 1.5 $";
340 senoner 1485 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
341     }
342    
343 persson 1887
344    
345 senoner 1485 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC