/[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 1715 - (hide annotations) (download)
Tue Mar 11 15:20:46 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 13422 byte(s)
* dispatch bank select as ordinary CC as well, the user might seriously
  want to (mis)use it for some purpose ("fixed" in all current MIDI
  input drivers: ALSA, CoreMIDI, JACK, MidiShare, MME)
* minor fix: only mark FX sends as being modified if really the
  respective FX send MIDI controller was used

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

  ViewVC Help
Powered by ViewVC