/[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 1500 - (hide annotations) (download)
Wed Nov 21 00:52:09 2007 UTC (16 years, 5 months ago) by senoner
File size: 13451 byte(s)
* win32 port, work in progress:
 - added ASIO low latency audio output driver
* MME MIDI input driver:
 - fixed number of PORTS to 1 as the win32 MME MIDI API
 allows to connect to only one MIDI port at time,

1 senoner 1485 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6     * Copyright (C) 2005 - 2007 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 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    
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 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     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     else
258     DispatchControlChange(data[1], data[2], data[0] & 0x0F);
259     break;
260    
261     case 0xD0:
262     DispatchControlChange(128, data[1], data[0] & 0x0F);
263     break;
264    
265     case 0xE0:
266     DispatchPitchbend(data[1], data[0] & 0x0F);
267     break;
268    
269     case 0x90:
270     if (data[1] < 0x80) {
271     if (data[2] > 0){
272     DispatchNoteOn(data[1], data[2], data[0] & 0x0F);
273     }else{
274     DispatchNoteOff(data[1], data[2], data[0] & 0x0F);
275     }
276     }
277     break;
278    
279     case 0x80:
280     if (data[1] < 0x80) {
281     DispatchNoteOff(data[1], data[2], data[0] & 0x0F);
282     }
283     break;
284    
285     case 0xC0:
286     if (data[1] < 0x80) {
287     DispatchProgramChange(data[1], data[0] & 0x0F);
288     }
289     break;
290     }
291    
292     break;
293    
294     case MIM_LONGDATA:
295     if(!ExitFlag) {
296     LPMIDIHDR lpMIDIHeader = (LPMIDIHDR)dwParam1;
297     DataPtr = (unsigned char *)(lpMIDIHeader->lpData);
298     if(lpMIDIHeader->dwBytesRecorded == 0) break;
299    
300     if(FirstSysExBlock) {
301     SysExOffset = 0;
302     FirstSysExBlock = false;
303     }
304    
305     if( DataPtr[lpMIDIHeader->dwBytesRecorded - 1] == 0xF7) {
306     SysExMsgComplete = true;
307     FirstSysExBlock = true;
308     }
309     else {
310     SysExMsgComplete = false;
311     }
312    
313     if(SysExOffset + lpMIDIHeader->dwBytesRecorded <= MME_MAX_SYSEX_BUF_SIZE) {
314     memcpy(&SysExBuf[SysExOffset], DataPtr, lpMIDIHeader->dwBytesRecorded);
315     SysExOffset += lpMIDIHeader->dwBytesRecorded;
316     }
317    
318     if(SysExMsgComplete) DispatchSysex(SysExBuf, SysExOffset);
319    
320     /* Queue the MIDIHDR for more input, only if ExitFlag was not set otherwise we risk an infinite loop
321     because when we call midiInReset() below, Windows will send a final MIM_LONGDATA message to that callback.
322     */
323     midiInAddBuffer(MidiInHandle, lpMIDIHeader, sizeof(MIDIHDR));
324     }
325     break;
326     }
327    
328     }
329    
330    
331    
332    
333     // *************** MidiInputDeviceMme ***************
334     // *
335    
336     MidiInputDeviceMme::MidiInputDeviceMme(std::map<String,DeviceCreationParameter*> Parameters, void* pSampler) : MidiInputDevice(Parameters, pSampler) {
337     AcquirePorts(((DeviceCreationParameterInt*)Parameters["PORTS"])->ValueAsInt());
338     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
339     Listen();
340     }
341     }
342    
343     MidiInputDeviceMme::~MidiInputDeviceMme() {
344     // free the midi ports (we can't let the base class do this,
345     // as the MidiInputPortMme destructors need access to
346     // hAlsaSeq)
347     for (std::map<int,MidiInputPort*>::iterator iter = Ports.begin(); iter != Ports.end() ; iter++) {
348     delete static_cast<MidiInputPortMme*>(iter->second);
349     }
350     Ports.clear();
351     }
352    
353     MidiInputDeviceMme::MidiInputPortMme* MidiInputDeviceMme::CreateMidiPort() {
354     return new MidiInputPortMme(this);
355     }
356    
357     String MidiInputDeviceMme::Name() {
358     return "MME";
359     }
360    
361     String MidiInputDeviceMme::Driver() {
362     return Name();
363     }
364    
365     void MidiInputDeviceMme::Listen() {
366     //TODO: ...
367     }
368    
369     void MidiInputDeviceMme::StopListen() {
370     //TODO: ...
371     }
372    
373     String MidiInputDeviceMme::Description() {
374     return "MultiMedia Extensions";
375     }
376    
377     String MidiInputDeviceMme::Version() {
378 senoner 1500 String s = "$Revision: 1.2 $";
379 senoner 1485 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
380     }
381    
382    
383    
384     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC