00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
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
00134
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
00170 if (midi_port2 != 0) {
00171 HMIDIOUT orig_midi_port = midi_port;
00172 HMIDIOUT orig_midi_port2 = midi_port2;
00173
00174
00175 midi_port2 = 0;
00176 send_sysex(status, msg, length);
00177
00178
00179 midi_port = orig_midi_port2;
00180 send_sysex(status, msg, length);
00181
00182
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
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
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
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