WindowsMidiDriver.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2005  The Pentagram Team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "WindowsMidiDriver.h"
00021 
00022 #ifdef USE_WINDOWS_MIDI
00023 
00024 const MidiDriver::MidiDriverDesc WindowsMidiDriver::desc = 
00025                 MidiDriver::MidiDriverDesc ("Windows", createInstance);
00026 
00027 using std::endl;
00028 
00029 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00030 #include "util.h"
00031 #endif
00032 
00033 #ifndef WIN32_LEAN_AND_MEAN
00034 #define WIN32_LEAN_AND_MEAN
00035 #endif
00036 
00037 #include <windows.h>
00038 #include <mmsystem.h>
00039 #include <winbase.h>
00040 #include <cstdlib>
00041 
00042 WindowsMidiDriver::WindowsMidiDriver() : 
00043         LowLevelMidiDriver(), dev_num(-1), midi_port(0), 
00044         _streamBuffer(0), _streamBufferSize(0), _streamEvent(0)
00045 {
00046 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00047         midi_port2 = 0;
00048 #endif
00049 }
00050 
00051 bool WindowsMidiDriver::doMCIError(MMRESULT mmsys_err)
00052 {
00053         if (mmsys_err != MMSYSERR_NOERROR)
00054         {
00055                 char buf[512];
00056                 midiOutGetErrorTextA(mmsys_err, buf, 512);
00057                 perr << buf << endl;
00058                 return true;
00059         }
00060         return false;
00061 }
00062 
00063 int WindowsMidiDriver::open()
00064 {
00065         int i;
00066         // Get Win32 Midi Device num
00067         std::string device;
00068 #ifdef PENTAGRAM_IN_EXULT
00069         device = getConfigSetting("win32_device", "-1");
00070 #else
00071         device = getConfigSetting("windows_midi_device", "-1");
00072 #endif
00073 
00074         const char *begin = device.c_str();
00075         char *end;
00076 
00077         dev_num = std::strtol(begin, &end, 10);
00078 
00079         // If not the terminator, we assume that the string was the device name, not num
00080         if (end[0]) dev_num = -1;
00081 
00082 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00083         dev_num = -1;
00084         int dev_num2 = -2;
00085 #endif
00086 
00087         // List all the midi devices.
00088         MIDIOUTCAPS caps;
00089         signed long dev_count = (signed long) midiOutGetNumDevs(); 
00090         pout << dev_count << " Midi Devices Detected" << endl;
00091         pout << "Listing midi devices:" << endl;
00092 
00093         for (i = -1; i < dev_count; i++)
00094         {
00095                 midiOutGetDevCaps ((UINT) i, &caps, sizeof(caps));
00096                 pout << i << ": " << caps.szPname << endl;
00097                 if (!Pentagram::strcasecmp(caps.szPname, device.c_str())) dev_num = i;
00098 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00099                 if (!Pentagram::strncasecmp(caps.szPname, "SB Live! Synth A", 16)) dev_num = i;
00100                 else if (!Pentagram::strncasecmp(caps.szPname, "SB Live! Synth B", 16)) dev_num2 = i;
00101 #endif
00102         }
00103 
00104         if (dev_num < -1 || dev_num >= dev_count)
00105         {
00106                 perr << "Warning Midi device in config is out of range." << endl;
00107                 dev_num = -1;
00108         }
00109 
00110         midiOutGetDevCaps ((UINT) dev_num, &caps, sizeof(caps));
00111         pout << "Using device " << dev_num << ": "<< caps.szPname << endl;
00112 
00113         _streamEvent = CreateEvent (NULL, true, true, NULL);
00114         UINT mmsys_err = midiOutOpen (&midi_port, dev_num, (uintptr) _streamEvent, 0, CALLBACK_EVENT);
00115 
00116 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00117         if (dev_num2 != -2 && mmsys_err != MMSYSERR_NOERROR)
00118         {
00119                 midiOutGetDevCaps ((UINT) dev_num2, &caps, sizeof(caps));
00120                 if (dev_num2 != -2) pout << "Using device " << dev_num2 << ": "<< caps.szPname << endl;
00121                 mmsys_err = midiOutOpen (&midi_port2, dev_num2, 0, 0, 0);
00122         }
00123 #endif
00124 
00125         if (doMCIError(mmsys_err))
00126         {
00127                 perr << "Error: Unable to open win32 midi device" << endl;
00128                 CloseHandle(_streamEvent);
00129                 _streamEvent = 0;
00130                 return 1;
00131         }
00132 
00133         // Set Win32 Midi Device num
00134         //config->set("config/audio/midi/win32_device", dev_num, true);
00135         
00136         return 0;
00137 }
00138 
00139 void WindowsMidiDriver::close()
00140 {
00141 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00142         if (midi_port2 != 0) midiOutClose (midi_port2);
00143         midi_port2 = 0;
00144 #endif
00145         midiOutClose (midi_port);
00146         midi_port = 0;
00147         CloseHandle(_streamEvent);
00148         _streamEvent = 0;
00149         delete [] _streamBuffer;
00150         _streamBuffer = 0;
00151         _streamBufferSize = 0;
00152 }
00153 
00154 void WindowsMidiDriver::send(uint32 message)
00155 {
00156 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00157         if (message & 0x1 && midi_port2 != 0) 
00158                 midiOutShortMsg (midi_port2,  message);
00159         else
00160                 midiOutShortMsg (midi_port,  message);
00161 #else
00162         midiOutShortMsg (midi_port,  message);
00163 #endif
00164 }
00165 
00166 void WindowsMidiDriver::send_sysex (uint8 status, const uint8 *msg, uint16 length)
00167 {
00168 #ifdef WIN32_USE_DUAL_MIDIDRIVERS
00169         // Hack for multiple devices. Not exactly 'fast'
00170         if (midi_port2 != 0) {
00171                 HMIDIOUT                        orig_midi_port = midi_port;
00172                 HMIDIOUT                        orig_midi_port2 = midi_port2;
00173 
00174                 // Send to port 1
00175                 midi_port2 = 0;
00176                 send_sysex(status, msg, length);
00177 
00178                 // Send to port 2
00179                 midi_port = orig_midi_port2;
00180                 send_sysex(status, msg, length);
00181 
00182                 // Return the ports to normal
00183                 midi_port = orig_midi_port;
00184                 midi_port2 = orig_midi_port2;
00185         }
00186 #endif
00187 
00188         if (WaitForSingleObject (_streamEvent, 2000) == WAIT_TIMEOUT) {
00189                 perr << "Error: Could not send SysEx - MMSYSTEM is still trying to send data after 2 seconds." << std::endl;
00190                 return;
00191         }
00192 
00193         if (_streamBuffer) {
00194                 MMRESULT result = midiOutUnprepareHeader (midi_port, &_streamHeader, sizeof (_streamHeader));
00195                 if (doMCIError(result)) {
00196                         //check_error (result);
00197                         perr << "Error: Could not send SysEx - midiOutUnprepareHeader failed." << std::endl;
00198                         return;
00199                 }
00200         }
00201 
00202         if (_streamBufferSize < length) {
00203                 delete [] _streamBuffer;
00204                 _streamBufferSize = length*2;
00205                 _streamBuffer = new uint8[_streamBufferSize];
00206         }
00207 
00208         _streamBuffer[0] = status;
00209         memcpy(_streamBuffer+1, msg, length);
00210 
00211         _streamHeader.lpData = (char *) _streamBuffer;
00212         _streamHeader.dwBufferLength = length + 1;
00213         _streamHeader.dwBytesRecorded = length + 1;
00214         _streamHeader.dwUser = 0;
00215         _streamHeader.dwFlags = 0;
00216 
00217         MMRESULT result = midiOutPrepareHeader (midi_port, &_streamHeader, sizeof (_streamHeader));
00218         if (doMCIError(result)) {
00219                 //check_error (result);
00220                 perr << "Error: Could not send SysEx - midiOutPrepareHeader failed." << std::endl;
00221                 return;
00222         }
00223 
00224         ResetEvent(_streamEvent);
00225         result = midiOutLongMsg (midi_port, &_streamHeader, sizeof (_streamHeader));
00226         if (doMCIError(result)) {
00227                 //check_error(result);
00228                 perr << "Error: Could not send SysEx - midiOutLongMsg failed." << std::endl;
00229                 SetEvent(_streamEvent);
00230                 return;
00231         }
00232 }
00233 
00234 void WindowsMidiDriver::increaseThreadPriority()
00235 {
00236         SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
00237 }
00238 
00239 void WindowsMidiDriver::yield()
00240 {
00241         Sleep(1);
00242 }
00243 
00244 #endif //WIN32

Generated on Fri Jul 27 22:27:53 2007 for pentagram by  doxygen 1.4.7