DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (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 along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #ifndef WIN32_LEAN_AND_MEAN 00021 #define WIN32_LEAN_AND_MEAN 00022 #endif 00023 #include <windows.h> 00024 #include <mmsystem.h> 00025 #include <string> 00026 #include <sstream> 00027 00028 #define WIN32_MIDI_PORT_PROTECT 1 00029 00030 class MidiHandler_win32: public MidiHandler { 00031 private: 00032 HMIDIOUT m_out = NULL; 00033 MIDIHDR m_hdr = {}; 00034 HANDLE m_event = NULL; 00035 bool isOpen; 00036 00037 #if WIN32_MIDI_PORT_PROTECT 00038 HINSTANCE hMidiHelper = NULL; 00039 bool midi_dll = false; 00040 bool midi_dll_active = false; 00041 00042 void MidiHelper_Reset() 00043 { 00044 midi_dll = false; 00045 midi_dll_active = false; 00046 00047 00048 // force unloading of old app - releases VSC lock 00049 hMidiHelper = LoadLibrary( "midi_helper.dll" ); 00050 if( hMidiHelper ) { 00051 midi_dll = true; 00052 while( FreeLibrary( hMidiHelper ) != 0 ) Sleep(1); 00053 } 00054 } 00055 00056 int MidiHelper_Start( DWORD devID ) 00057 { 00058 HMIDIOUT (*func_ptr)(DWORD); 00059 00060 hMidiHelper = LoadLibrary( "midi_helper.dll" ); 00061 if( !hMidiHelper ) return -1; 00062 00063 func_ptr = (HMIDIOUT(*)(DWORD))GetProcAddress( hMidiHelper,"MIDIHelper_OpenMidiOut" ); 00064 if (!func_ptr ) return -1; 00065 00066 m_out = func_ptr( devID ); 00067 if( m_out == 0 ) return -1; 00068 00069 00070 midi_dll_active = true; 00071 return 0; 00072 } 00073 00074 void MidiHelper_End() 00075 { 00076 void (*func_ptr)(void); 00077 00078 00079 func_ptr = (void(*)(void))GetProcAddress( hMidiHelper,"MIDIHelper_CloseMidiOut" ); 00080 if (!func_ptr ) return; 00081 00082 func_ptr(); 00083 } 00084 #endif 00085 00086 public: 00087 MidiHandler_win32() : MidiHandler(),isOpen(false) {}; 00088 const char * GetName(void) { return "win32";}; 00089 00090 bool Open(const char * conf) { 00091 MIDIOUTCAPS mididev; 00092 if (isOpen) return false; 00093 00094 00095 #if WIN32_MIDI_PORT_PROTECT 00096 // VSC crash protection 00097 MidiHelper_Reset(); 00098 #endif 00099 00100 00101 m_event = CreateEvent (NULL, true, true, NULL); 00102 MMRESULT res = MMSYSERR_NOERROR; 00103 if(conf && *conf) { 00104 std::string strconf(conf); 00105 std::istringstream configmidi(strconf); 00106 unsigned int total = midiOutGetNumDevs(); 00107 unsigned int nummer = total; 00108 configmidi >> nummer; 00109 if (configmidi.fail() && total) { 00110 lowcase(strconf); 00111 for(unsigned int i = 0; i< total;i++) { 00112 midiOutGetDevCaps(i, &mididev, sizeof(MIDIOUTCAPS)); 00113 std::string devname(mididev.szPname); 00114 lowcase(devname); 00115 if (devname.find(strconf) != std::string::npos) { 00116 nummer = i; 00117 break; 00118 } 00119 } 00120 } 00121 00122 if (nummer < total) { 00123 midiOutGetDevCaps(nummer, &mididev, sizeof(MIDIOUTCAPS)); 00124 LOG_MSG("MIDI:win32 selected %s",mididev.szPname); 00125 00126 00127 #if WIN32_MIDI_PORT_PROTECT 00128 if( midi_dll == false || strcmp( mididev.szPname, "Roland VSC" ) != 0 ) 00129 res = midiOutOpen(&m_out, nummer, (DWORD_PTR)m_event, 0, CALLBACK_EVENT); 00130 else { 00131 // Roland VSC - crash protection 00132 res = MidiHelper_Start(nummer); 00133 } 00134 #else 00135 res = midiOutOpen(&m_out, nummer, (DWORD_PTR)m_event, 0, CALLBACK_EVENT); 00136 #endif 00137 00138 00139 if( res != MMSYSERR_NOERROR ) { 00140 if( strcmp( mididev.szPname, "Roland VSC" ) == 0 ) MessageBox( 0, "Roland VSC failed", "MIDI", MB_OK | MB_TOPMOST ); 00141 00142 if( nummer != 0 ) { 00143 LOG_MSG("MIDI:win32 selected %s","default"); 00144 res = midiOutOpen(&m_out, MIDI_MAPPER, (DWORD_PTR)m_event, 0, CALLBACK_EVENT); 00145 } 00146 } 00147 } 00148 } else { 00149 res = midiOutOpen(&m_out, MIDI_MAPPER, (DWORD_PTR)m_event, 0, CALLBACK_EVENT); 00150 } 00151 if (res != MMSYSERR_NOERROR) return false; 00152 00153 Reset(); 00154 00155 isOpen=true; 00156 return true; 00157 }; 00158 00159 void Close(void) { 00160 if (!isOpen) return; 00161 isOpen=false; 00162 00163 00164 #if WIN32_MIDI_PORT_PROTECT 00165 if( midi_dll ) MidiHelper_End(); 00166 #endif 00167 00168 // flush buffers, then shutdown 00169 midiOutReset(m_out); 00170 midiOutClose(m_out); 00171 00172 CloseHandle (m_event); 00173 }; 00174 00175 void PlayMsg(Bit8u * msg) { 00176 midiOutShortMsg(m_out, *(Bit32u*)msg); 00177 }; 00178 00179 void PlaySysex(Bit8u * sysex,Bitu len) { 00180 #if WIN32_MIDI_PORT_PROTECT 00181 if( midi_dll_active == false ) { 00182 #endif 00183 if (WaitForSingleObject (m_event, 2000) == WAIT_TIMEOUT) { 00184 LOG(LOG_MISC,LOG_ERROR)("Can't send midi message"); 00185 return; 00186 } 00187 #if WIN32_MIDI_PORT_PROTECT 00188 } 00189 #endif 00190 00191 midiOutUnprepareHeader (m_out, &m_hdr, sizeof (m_hdr)); 00192 00193 m_hdr.lpData = (char *) sysex; 00194 m_hdr.dwBufferLength = (DWORD)len; 00195 m_hdr.dwBytesRecorded = (DWORD)len; 00196 m_hdr.dwUser = 0; 00197 00198 MMRESULT result = midiOutPrepareHeader (m_out, &m_hdr, sizeof (m_hdr)); 00199 if (result != MMSYSERR_NOERROR) return; 00200 ResetEvent (m_event); 00201 result = midiOutLongMsg (m_out,&m_hdr,sizeof(m_hdr)); 00202 if (result != MMSYSERR_NOERROR) { 00203 SetEvent (m_event); 00204 return; 00205 } 00206 00207 #if WIN32_MIDI_PORT_PROTECT 00208 if( midi_dll_active == true ) { 00209 while( midiOutUnprepareHeader (m_out, &m_hdr, sizeof (m_hdr)) != 0 ) 00210 Sleep(1); 00211 } 00212 #endif 00213 } 00214 00215 void ListAll(Program* base) { 00216 #if defined (WIN32) 00217 unsigned int total = midiOutGetNumDevs(); 00218 for(unsigned int i = 0;i < total;i++) { 00219 MIDIOUTCAPS mididev; 00220 midiOutGetDevCaps(i, &mididev, sizeof(MIDIOUTCAPS)); 00221 base->WriteOut("%2d\t \"%s\"\n",i,mididev.szPname); 00222 } 00223 #endif 00224 } 00225 00226 void Reset() 00227 { 00228 Bit8u buf[64]; 00229 00230 // flush buffers 00231 midiOutReset(m_out); 00232 00233 00234 // GM1 reset 00235 buf[0] = 0xf0; 00236 buf[1] = 0x7e; 00237 buf[2] = 0x7f; 00238 buf[3] = 0x09; 00239 buf[4] = 0x01; 00240 buf[5] = 0xf7; 00241 PlaySysex( (Bit8u *) buf, 6 ); 00242 00243 00244 // GS1 reset 00245 buf[0] = 0xf0; 00246 buf[1] = 0x41; 00247 buf[2] = 0x10; 00248 buf[3] = 0x42; 00249 buf[4] = 0x12; 00250 buf[5] = 0x40; 00251 buf[6] = 0x00; 00252 buf[7] = 0x7f; 00253 buf[8] = 0x00; 00254 buf[9] = 0x41; 00255 buf[10] = 0xf7; 00256 PlaySysex( (Bit8u *) buf, 11 ); 00257 } 00258 }; 00259 00260 MidiHandler_win32 Midi_win32;