DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/gui/midi_win32.h
00001 /*
00002  *  Copyright (C) 2002-2015  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
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 
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;
00033         MIDIHDR m_hdr;
00034         HANDLE m_event;
00035         bool isOpen;
00036 
00037 #if WIN32_MIDI_PORT_PROTECT
00038         HINSTANCE hMidiHelper;
00039         bool midi_dll;
00040         bool midi_dll_active;
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 nummer = midiOutGetNumDevs();
00107                         configmidi >> nummer;
00108                         if(nummer < midiOutGetNumDevs()){
00109                                 midiOutGetDevCaps(nummer, &mididev, sizeof(MIDIOUTCAPS));
00110                                 LOG_MSG("MIDI:win32 selected %s",mididev.szPname);
00111 
00112 
00113 #if WIN32_MIDI_PORT_PROTECT
00114                                 if( midi_dll == false || strcmp( mididev.szPname, "Roland VSC" ) != 0 )
00115                                         res = midiOutOpen(&m_out, nummer, PtrToUlong(m_event), 0, CALLBACK_EVENT);
00116                                 else {
00117                                         // Roland VSC - crash protection
00118                                         res = MidiHelper_Start(nummer);
00119                                 }
00120 #else
00121                                 res = midiOutOpen(&m_out, nummer, PtrToUlong(m_event), 0, CALLBACK_EVENT);
00122 #endif
00123 
00124 
00125                                 if( res != MMSYSERR_NOERROR ) {
00126                                         if( strcmp( mididev.szPname, "Roland VSC" ) == 0 ) MessageBox( 0, "Roland VSC failed", "MIDI", MB_OK | MB_TOPMOST );
00127 
00128                                         if( nummer != 0 ) {
00129                                                 LOG_MSG("MIDI:win32 selected %s","default");
00130                                                 res = midiOutOpen(&m_out, MIDI_MAPPER, PtrToUlong(m_event), 0, CALLBACK_EVENT);
00131                                         }
00132                                 }
00133                         }
00134                 } else {
00135                         res = midiOutOpen(&m_out, MIDI_MAPPER, PtrToUlong(m_event), 0, CALLBACK_EVENT);
00136                 }
00137                 if (res != MMSYSERR_NOERROR) return false;
00138 
00139                 Reset();
00140 
00141                 isOpen=true;
00142                 return true;
00143         };
00144 
00145         void Close(void) {
00146                 if (!isOpen) return;
00147                 isOpen=false;
00148 
00149 
00150 #if WIN32_MIDI_PORT_PROTECT
00151                 if( midi_dll ) MidiHelper_End();
00152 #endif
00153 
00154                 // flush buffers, then shutdown
00155                 midiOutReset(m_out);
00156                 midiOutClose(m_out);
00157 
00158                 CloseHandle (m_event);
00159         };
00160 
00161         void PlayMsg(Bit8u * msg) {
00162                 midiOutShortMsg(m_out, *(Bit32u*)msg);
00163         };
00164 
00165         void PlaySysex(Bit8u * sysex,Bitu len) {
00166 #if WIN32_MIDI_PORT_PROTECT
00167                 if( midi_dll_active == false ) {
00168 #endif
00169                         if (WaitForSingleObject (m_event, 2000) == WAIT_TIMEOUT) {
00170                                 LOG(LOG_MISC,LOG_ERROR)("Can't send midi message");
00171                                 return;
00172                         }
00173 #if WIN32_MIDI_PORT_PROTECT
00174                 }
00175 #endif
00176 
00177                 midiOutUnprepareHeader (m_out, &m_hdr, sizeof (m_hdr));
00178 
00179                 m_hdr.lpData = (char *) sysex;
00180                 m_hdr.dwBufferLength = len ;
00181                 m_hdr.dwBytesRecorded = len ;
00182                 m_hdr.dwUser = 0;
00183 
00184                 MMRESULT result = midiOutPrepareHeader (m_out, &m_hdr, sizeof (m_hdr));
00185                 if (result != MMSYSERR_NOERROR) return;
00186                 ResetEvent (m_event);
00187                 result = midiOutLongMsg (m_out,&m_hdr,sizeof(m_hdr));
00188                 if (result != MMSYSERR_NOERROR) {
00189                         SetEvent (m_event);
00190                         return;
00191                 }
00192 
00193 #if WIN32_MIDI_PORT_PROTECT
00194                 if( midi_dll_active == true ) {
00195                         while( midiOutUnprepareHeader (m_out, &m_hdr, sizeof (m_hdr)) != 0 )
00196                                 Sleep(1);
00197                 }
00198 #endif
00199         }
00200 
00201         void Reset()
00202         {
00203                 Bit8u buf[64];
00204 
00205                 // flush buffers
00206                 midiOutReset(m_out);
00207 
00208 
00209                 // GM1 reset
00210                 buf[0] = 0xf0;
00211                 buf[1] = 0x7e;
00212                 buf[2] = 0x7f;
00213                 buf[3] = 0x09;
00214                 buf[4] = 0x01;
00215                 buf[5] = 0xf7;
00216                 PlaySysex( (Bit8u *) buf, 6 );
00217 
00218 
00219                 // GS1 reset
00220                 buf[0] = 0xf0;
00221                 buf[1] = 0x41;
00222                 buf[2] = 0x10;
00223                 buf[3] = 0x42;
00224                 buf[4] = 0x12;
00225                 buf[5] = 0x40;
00226                 buf[6] = 0x00;
00227                 buf[7] = 0x7f;
00228                 buf[8] = 0x00;
00229                 buf[9] = 0x41;
00230                 buf[10] = 0xf7;
00231                 PlaySysex( (Bit8u *) buf, 11 );
00232         }
00233 };
00234 
00235 MidiHandler_win32 Midi_win32;