├── LICENSE.txt ├── README ├── README.txt ├── common └── settings.h ├── driver ├── VSTDriver.cpp ├── VSTDriver.h ├── buildvs.bat ├── buildvs_debug.bat ├── ds_stream.h ├── dsound.cpp ├── mmddk.h ├── sound_out.h ├── sound_out_dsound.cpp ├── sound_out_xaudio2.cpp ├── vstmididrv.cpp ├── vstmididrv.def ├── vstmididrv.sln └── vstmididrv.vcxproj ├── drivercfg ├── DlgTabCtrl.h ├── MainDlg.h ├── Views.h ├── drivercfg.cpp ├── drivercfg.h ├── drivercfg.ico ├── drivercfg.rc ├── drivercfg.sln ├── drivercfg.vcxproj ├── drivercfg.vcxproj.user ├── res │ └── drivercfg.ico ├── resource.h ├── small.ico ├── stdafx.cpp ├── stdafx.h ├── targetver.h └── utf8conv.h ├── external_packages ├── XAudio2.h ├── aeffect.h ├── aeffectx.h ├── audiodefs.h ├── comdecl.h └── xma2defs.h ├── vsthost ├── resource.h ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── vsthost.cpp ├── vsthost.ico ├── vsthost.rc ├── vsthost.sln ├── vsthost.vcxproj └── vsthost.vcxproj.filters └── vstmididrv.nsi /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/README -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | VST DirectMusic/WinMM Driver 2 | ******************************** 3 | 4 | First-time Installation 5 | ----------------------- 6 | 7 | Simply run the installer. 8 | 9 | 10 | Upgrading 11 | --------- 12 | 13 | Run the downloaded installer. It will ask you to remove old versions. 14 | Only then, you can install a upgraded version. 15 | 16 | 17 | License 18 | ------- 19 | 20 | Copyright (C) 2011 Chris Moeller, Brad Miller 21 | 22 | This library is free software; you can redistribute it and/or 23 | modify it under the terms of the GNU Lesser General Public 24 | License as published by the Free Software Foundation; either 25 | version 2.1 of the License, or (at your option) any later version. 26 | 27 | This library is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 | Lesser General Public License for more details. 31 | 32 | You should have received a copy of the GNU Lesser General Public 33 | License along with this library; if not, write to the Free Software 34 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -------------------------------------------------------------------------------- /common/settings.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../external_packages/aeffect.h" 5 | 6 | template 7 | static void append_be( std::vector & out, const T & value ) 8 | { 9 | union 10 | { 11 | T original; 12 | std::uint8_t raw[sizeof(T)]; 13 | } carriage; 14 | carriage.original = value; 15 | for ( unsigned i = 0; i < sizeof(T); ++i ) 16 | { 17 | out.push_back( carriage.raw[ sizeof(T) - 1 - i ] ); 18 | } 19 | } 20 | 21 | template 22 | static void retrieve_be( T & out, const std::uint8_t * & in, unsigned & size ) 23 | { 24 | if ( size < sizeof(T) ) return; 25 | 26 | size -= sizeof(T); 27 | 28 | union 29 | { 30 | T original; 31 | std::uint8_t raw[sizeof(T)]; 32 | } carriage; 33 | for ( unsigned i = 0; i < sizeof(T); ++i ) 34 | { 35 | carriage.raw[ sizeof(T) - 1 - i ] = *in++; 36 | } 37 | 38 | out = carriage.original; 39 | } 40 | 41 | static void getChunk( AEffect * pEffect, std::vector & out ) 42 | { 43 | out.resize( 0 ); 44 | std::uint32_t unique_id = pEffect->uniqueID; 45 | append_be( out, unique_id ); 46 | bool type_chunked = !!( pEffect->flags & effFlagsProgramChunks ); 47 | append_be( out, type_chunked ); 48 | if ( !type_chunked ) 49 | { 50 | std::uint32_t num_params = pEffect->numParams; 51 | append_be( out, num_params ); 52 | for ( unsigned i = 0; i < num_params; ++i ) 53 | { 54 | float parameter = pEffect->getParameter( pEffect, i ); 55 | append_be( out, parameter ); 56 | } 57 | } 58 | else 59 | { 60 | void * chunk; 61 | std::uint32_t size = pEffect->dispatcher( pEffect, effGetChunk, 0, 0, &chunk, 0 ); 62 | append_be( out, size ); 63 | size_t chunk_size = out.size(); 64 | out.resize( chunk_size + size ); 65 | std::memcpy( &out[ chunk_size ], chunk, size ); 66 | } 67 | } 68 | 69 | static void setChunk( AEffect * pEffect, std::vector const& in ) 70 | { 71 | unsigned size = in.size(); 72 | if ( pEffect && size ) 73 | { 74 | const std::uint8_t * inc = in.data(); 75 | std::uint32_t effect_id; 76 | retrieve_be( effect_id, inc, size ); 77 | if ( effect_id != pEffect->uniqueID ) return; 78 | bool type_chunked; 79 | retrieve_be( type_chunked, inc, size ); 80 | if ( type_chunked != !!( pEffect->flags & effFlagsProgramChunks ) ) return; 81 | if ( !type_chunked ) 82 | { 83 | std::uint32_t num_params; 84 | retrieve_be( num_params, inc, size ); 85 | if ( num_params != pEffect->numParams ) return; 86 | for ( unsigned i = 0; i < num_params; ++i ) 87 | { 88 | float parameter; 89 | retrieve_be( parameter, inc, size ); 90 | pEffect->setParameter( pEffect, i, parameter ); 91 | } 92 | } 93 | else 94 | { 95 | std::uint32_t chunk_size; 96 | retrieve_be( chunk_size, inc, size ); 97 | if ( chunk_size > size ) return; 98 | pEffect->dispatcher( pEffect, effSetChunk, 0, chunk_size, ( void * ) inc, 0 ); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /driver/VSTDriver.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 Chris Moeller, Brad Miller 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU Lesser General Public License as published by 5 | * the Free Software Foundation, either version 2.1 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include "VSTDriver.h" 18 | 19 | #include 20 | 21 | VSTDriver::VSTDriver() { 22 | szPluginPath = NULL; 23 | bInitialized = false; 24 | hProcess = NULL; 25 | hThread = NULL; 26 | hReadEvent = NULL; 27 | hChildStd = NULL; 28 | uNumOutputs = 0; 29 | sName = NULL; 30 | sVendor = NULL; 31 | sProduct = NULL; 32 | } 33 | 34 | VSTDriver::~VSTDriver() { 35 | CloseVSTDriver(); 36 | delete [] sName; 37 | delete [] sVendor; 38 | delete [] sProduct; 39 | } 40 | 41 | static WORD getwordle(BYTE *pData) 42 | { 43 | return (WORD)(pData[0] | (((WORD)pData[1]) << 8)); 44 | } 45 | 46 | static DWORD getdwordle(BYTE *pData) 47 | { 48 | return pData[0] | (((DWORD)pData[1]) << 8) | (((DWORD)pData[2]) << 16) | (((DWORD)pData[3]) << 24); 49 | } 50 | 51 | unsigned VSTDriver::test_plugin_platform() { 52 | #define iMZHeaderSize (0x40) 53 | #define iPEHeaderSize (4 + 20 + 224) 54 | 55 | BYTE peheader[iPEHeaderSize]; 56 | DWORD dwOffsetPE; 57 | 58 | FILE * f = _tfopen( szPluginPath, _T("rb") ); 59 | if ( !f ) goto error; 60 | if ( fread( peheader, 1, iMZHeaderSize, f ) < iMZHeaderSize ) goto error; 61 | if ( getwordle(peheader) != 0x5A4D ) goto error; 62 | dwOffsetPE = getdwordle( peheader + 0x3c ); 63 | if ( fseek( f, dwOffsetPE, SEEK_SET ) != 0 ) goto error; 64 | if ( fread( peheader, 1, iPEHeaderSize, f ) < iPEHeaderSize ) goto error; 65 | fclose( f ); f = NULL; 66 | if ( getdwordle( peheader ) != 0x00004550 ) goto error; 67 | switch ( getwordle( peheader + 4 ) ) { 68 | case 0x014C: return 32; 69 | case 0x8664: return 64; 70 | } 71 | 72 | error: 73 | if ( f ) fclose( f ); 74 | return 0; 75 | } 76 | 77 | void VSTDriver::load_settings(TCHAR * szPath) { 78 | HKEY hKey; 79 | long lResult; 80 | DWORD dwType=REG_SZ; 81 | DWORD dwSize=0; 82 | if ( szPath || RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\VSTi Driver"),0,KEY_READ|KEY_WOW64_32KEY,&hKey) == ERROR_SUCCESS ) { 83 | if ( !szPath ) lResult = RegQueryValueEx(hKey, _T("plugin"), NULL, &dwType, NULL, &dwSize); 84 | if ( szPath || ( lResult == ERROR_SUCCESS && dwType == REG_SZ ) ) { 85 | if ( szPath ) dwSize = _tcslen( szPath ) * sizeof(TCHAR); 86 | szPluginPath = (TCHAR*) calloc( dwSize + sizeof(TCHAR), 1 ); 87 | if ( szPath ) _tcscpy( szPluginPath, szPath ); 88 | else RegQueryValueEx(hKey, _T("plugin"), NULL, &dwType, (LPBYTE) szPluginPath, &dwSize); 89 | 90 | uPluginPlatform = test_plugin_platform(); 91 | 92 | blChunk.resize( 0 ); 93 | 94 | const TCHAR * dot = _tcsrchr( szPluginPath, _T('.') ); 95 | if ( !dot ) dot = szPluginPath + _tcslen( szPluginPath ); 96 | TCHAR * szSettingsPath = ( TCHAR * ) _alloca( ( dot - szPluginPath + 5 ) * sizeof( TCHAR ) ); 97 | _tcsncpy( szSettingsPath, szPluginPath, dot - szPluginPath ); 98 | _tcscpy( szSettingsPath + ( dot - szPluginPath ), _T(".set") ); 99 | 100 | FILE * f; 101 | errno_t err = _tfopen_s( &f, szSettingsPath, _T("rb") ); 102 | if ( !err ) 103 | { 104 | fseek( f, 0, SEEK_END ); 105 | size_t chunk_size = ftell( f ); 106 | fseek( f, 0, SEEK_SET ); 107 | blChunk.resize( chunk_size ); 108 | fread( blChunk.data(), 1, chunk_size, f ); 109 | fclose( f ); 110 | } 111 | } 112 | if ( !szPath ) RegCloseKey( hKey); 113 | } 114 | } 115 | 116 | static inline char print_hex_digit(unsigned val) 117 | { 118 | static const char table[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 119 | assert((val & ~0xF) == 0); 120 | return table[val]; 121 | } 122 | 123 | static void print_hex(unsigned val,std::wstring &out,unsigned bytes) 124 | { 125 | unsigned n; 126 | for(n=0;n> ((bytes - 1 - n) << 3)) & 0xFF); 129 | out += print_hex_digit( c >> 4 ); 130 | out += print_hex_digit( c & 0xF ); 131 | } 132 | } 133 | 134 | static void print_guid(const GUID & p_guid, std::wstring &out) 135 | { 136 | print_hex(p_guid.Data1,out,4); 137 | out += '-'; 138 | print_hex(p_guid.Data2,out,2); 139 | out += '-'; 140 | print_hex(p_guid.Data3,out,2); 141 | out += '-'; 142 | print_hex(p_guid.Data4[0],out,1); 143 | print_hex(p_guid.Data4[1],out,1); 144 | out += '-'; 145 | print_hex(p_guid.Data4[2],out,1); 146 | print_hex(p_guid.Data4[3],out,1); 147 | print_hex(p_guid.Data4[4],out,1); 148 | print_hex(p_guid.Data4[5],out,1); 149 | print_hex(p_guid.Data4[6],out,1); 150 | print_hex(p_guid.Data4[7],out,1); 151 | } 152 | 153 | static bool create_pipe_name( std::wstring & out ) 154 | { 155 | GUID guid; 156 | if ( FAILED( CoCreateGuid( &guid ) ) ) return false; 157 | 158 | out = L"\\\\.\\pipe\\"; 159 | print_guid( guid, out ); 160 | 161 | return true; 162 | } 163 | 164 | bool VSTDriver::connect_pipe( HANDLE hPipe ) 165 | { 166 | OVERLAPPED ol = {}; 167 | ol.hEvent = hReadEvent; 168 | ResetEvent( hReadEvent ); 169 | if ( !ConnectNamedPipe( hPipe, &ol ) ) 170 | { 171 | DWORD error = GetLastError(); 172 | if ( error == ERROR_PIPE_CONNECTED ) return true; 173 | if ( error != ERROR_IO_PENDING ) return false; 174 | 175 | if ( WaitForSingleObject( hReadEvent, 10000 ) == WAIT_TIMEOUT ) return false; 176 | } 177 | return true; 178 | } 179 | 180 | extern "C" { extern HINSTANCE hinst_vst_driver; }; 181 | 182 | bool VSTDriver::process_create() 183 | { 184 | if ( uPluginPlatform != 32 && uPluginPlatform != 64 ) return false; 185 | 186 | SECURITY_ATTRIBUTES saAttr; 187 | 188 | saAttr.nLength = sizeof(saAttr); 189 | saAttr.bInheritHandle = TRUE; 190 | saAttr.lpSecurityDescriptor = NULL; 191 | 192 | if ( !bInitialized ) 193 | { 194 | if ( FAILED( CoInitialize( NULL ) ) ) return false; 195 | bInitialized = true; 196 | } 197 | 198 | hReadEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 199 | 200 | std::wstring pipe_name; 201 | if ( !create_pipe_name( pipe_name ) ) 202 | { 203 | process_terminate(); 204 | return false; 205 | } 206 | 207 | HANDLE hPipe = CreateNamedPipe( pipe_name.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 65536, 65536, 0, &saAttr ); 208 | DuplicateHandle( GetCurrentProcess(), hPipe, GetCurrentProcess(), &hChildStd, 0, FALSE, DUPLICATE_SAME_ACCESS ); 209 | 210 | std::wstring szCmdLine = L"\""; 211 | 212 | TCHAR my_path[MAX_PATH]; 213 | GetModuleFileName( hinst_vst_driver, my_path, _countof(my_path) ); 214 | 215 | szCmdLine += my_path; 216 | szCmdLine.resize( szCmdLine.find_last_of( '\\' ) + 1 ); 217 | szCmdLine += (uPluginPlatform == 64) ? L"vsthost64.exe" : L"vsthost32.exe"; 218 | szCmdLine += L"\" \""; 219 | szCmdLine += szPluginPath; 220 | szCmdLine += L"\" "; 221 | 222 | unsigned sum = 0; 223 | 224 | const TCHAR * ch = szPluginPath; 225 | while ( *ch ) 226 | { 227 | sum += (TCHAR)( *ch++ * 820109 ); 228 | } 229 | 230 | print_hex( sum, szCmdLine, 4 ); 231 | 232 | szCmdLine += L" "; 233 | szCmdLine += pipe_name.c_str() + 9; 234 | 235 | PROCESS_INFORMATION piProcInfo; 236 | STARTUPINFO siStartInfo = {0}; 237 | 238 | siStartInfo.cb = sizeof(siStartInfo); 239 | 240 | TCHAR CmdLine[MAX_PATH]; 241 | _tcscpy_s(CmdLine, _countof(CmdLine), szCmdLine.c_str()); 242 | 243 | if ( !CreateProcess( NULL, CmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo ) ) 244 | { 245 | process_terminate(); 246 | return false; 247 | } 248 | 249 | hProcess = piProcInfo.hProcess; 250 | hThread = piProcInfo.hThread; 251 | 252 | #ifdef NDEBUG 253 | SetPriorityClass( hProcess, GetPriorityClass( GetCurrentProcess() ) ); 254 | SetThreadPriority( hThread, GetThreadPriority( GetCurrentThread() ) ); 255 | #endif 256 | 257 | if ( !connect_pipe( hChildStd ) ) 258 | { 259 | process_terminate(); 260 | return false; 261 | } 262 | 263 | uint32_t code = process_read_code(); 264 | 265 | if ( code != 0 ) 266 | { 267 | process_terminate(); 268 | return false; 269 | } 270 | 271 | uint32_t name_string_length = process_read_code(); 272 | uint32_t vendor_string_length = process_read_code(); 273 | uint32_t product_string_length = process_read_code(); 274 | uVendorVersion = process_read_code(); 275 | uUniqueId = process_read_code(); 276 | uNumOutputs = process_read_code(); 277 | 278 | delete [] sName; 279 | delete [] sVendor; 280 | delete [] sProduct; 281 | 282 | sName = new char[ name_string_length + 1 ]; 283 | sVendor = new char[ vendor_string_length + 1 ]; 284 | sProduct = new char[ product_string_length + 1 ]; 285 | 286 | process_read_bytes( sName, name_string_length ); 287 | process_read_bytes( sVendor, vendor_string_length ); 288 | process_read_bytes( sProduct, product_string_length ); 289 | 290 | sName[ name_string_length ] = 0; 291 | sVendor[ vendor_string_length ] = 0; 292 | sProduct[ product_string_length ] = 0; 293 | 294 | return true; 295 | } 296 | 297 | void VSTDriver::process_terminate() 298 | { 299 | if ( hProcess ) 300 | { 301 | process_write_code( 0 ); 302 | WaitForSingleObject( hProcess, 5000 ); 303 | TerminateProcess( hProcess, 0 ); 304 | CloseHandle( hThread ); 305 | CloseHandle( hProcess ); 306 | } 307 | if ( hChildStd ) CloseHandle( hChildStd ); 308 | if ( hReadEvent ) CloseHandle( hReadEvent ); 309 | if ( bInitialized ) CoUninitialize(); 310 | bInitialized = false; 311 | hProcess = NULL; 312 | hThread = NULL; 313 | hReadEvent = NULL; 314 | hChildStd = NULL; 315 | } 316 | 317 | bool VSTDriver::process_running() 318 | { 319 | if ( hProcess && WaitForSingleObject( hProcess, 0 ) == WAIT_TIMEOUT ) return true; 320 | return false; 321 | } 322 | 323 | static void ProcessPendingMessages() 324 | { 325 | MSG msg = {}; 326 | while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) DispatchMessage( &msg ); 327 | } 328 | 329 | uint32_t VSTDriver::process_read_bytes_pass( void * out, uint32_t size ) 330 | { 331 | OVERLAPPED ol = {}; 332 | ol.hEvent = hReadEvent; 333 | ResetEvent( hReadEvent ); 334 | DWORD bytesDone; 335 | SetLastError( NO_ERROR ); 336 | if ( ReadFile( hChildStd, out, size, &bytesDone, &ol ) ) return bytesDone; 337 | if ( GetLastError() != ERROR_IO_PENDING ) return 0; 338 | 339 | const HANDLE handles[1] = {hReadEvent}; 340 | SetLastError( NO_ERROR ); 341 | DWORD state; 342 | for (;;) 343 | { 344 | state = MsgWaitForMultipleObjects( _countof( handles ), handles, FALSE, INFINITE, QS_ALLEVENTS ); 345 | if ( state == WAIT_OBJECT_0 + _countof( handles ) ) ProcessPendingMessages(); 346 | else break; 347 | } 348 | 349 | if ( state == WAIT_OBJECT_0 && GetOverlappedResult( hChildStd, &ol, &bytesDone, TRUE ) ) return bytesDone; 350 | 351 | #if 0 && _WIN32_WINNT >= 0x600 352 | CancelIoEx( hChildStd, &ol ); 353 | #else 354 | CancelIo( hChildStd ); 355 | #endif 356 | 357 | return 0; 358 | } 359 | 360 | void VSTDriver::process_read_bytes( void * out, uint32_t size ) 361 | { 362 | if ( process_running() && size ) 363 | { 364 | uint8_t * ptr = (uint8_t *) out; 365 | uint32_t done = 0; 366 | while ( done < size ) 367 | { 368 | uint32_t delta = process_read_bytes_pass( ptr + done, size - done ); 369 | if ( delta == 0 ) 370 | { 371 | memset( out, 0xFF, size ); 372 | break; 373 | } 374 | done += delta; 375 | } 376 | } 377 | else memset( out, 0xFF, size ); 378 | } 379 | 380 | uint32_t VSTDriver::process_read_code() 381 | { 382 | uint32_t code; 383 | process_read_bytes( &code, sizeof(code) ); 384 | return code; 385 | } 386 | 387 | void VSTDriver::process_write_bytes( const void * in, uint32_t size ) 388 | { 389 | if ( process_running() ) 390 | { 391 | if ( size == 0 ) return; 392 | DWORD bytesWritten; 393 | if ( !WriteFile( hChildStd, in, size, &bytesWritten, NULL ) || bytesWritten < size ) process_terminate(); 394 | } 395 | } 396 | 397 | void VSTDriver::process_write_code( uint32_t code ) 398 | { 399 | process_write_bytes( &code, sizeof(code) ); 400 | } 401 | 402 | void VSTDriver::getEffectName(std::string & out) 403 | { 404 | out = sName; 405 | } 406 | 407 | void VSTDriver::getVendorString(std::string & out) 408 | { 409 | out = sVendor; 410 | } 411 | 412 | void VSTDriver::getProductString(std::string & out) 413 | { 414 | out = sProduct; 415 | } 416 | 417 | long VSTDriver::getVendorVersion() 418 | { 419 | return uVendorVersion; 420 | } 421 | 422 | long VSTDriver::getUniqueID() 423 | { 424 | return uUniqueId; 425 | } 426 | 427 | void VSTDriver::getChunk( std::vector & out ) 428 | { 429 | process_write_code( 1 ); 430 | 431 | uint32_t code = process_read_code(); 432 | 433 | if ( code == 0 ) 434 | { 435 | uint32_t size = process_read_code(); 436 | 437 | out.resize( size ); 438 | 439 | process_read_bytes( &out[0], size ); 440 | } 441 | else process_terminate(); 442 | } 443 | 444 | void VSTDriver::setChunk( const void * in, unsigned size ) 445 | { 446 | process_write_code( 2 ); 447 | process_write_code( size ); 448 | process_write_bytes( in, size ); 449 | uint32_t code = process_read_code(); 450 | if ( code != 0 ) process_terminate(); 451 | } 452 | 453 | bool VSTDriver::hasEditor() 454 | { 455 | process_write_code( 3 ); 456 | uint32_t code = process_read_code(); 457 | if ( code != 0 ) 458 | { 459 | process_terminate(); 460 | return false; 461 | } 462 | code = process_read_code(); 463 | return code != 0; 464 | } 465 | 466 | void VSTDriver::displayEditorModal() 467 | { 468 | process_write_code( 4 ); 469 | uint32_t code = process_read_code(); 470 | if ( code != 0 ) process_terminate(); 471 | } 472 | 473 | void VSTDriver::CloseVSTDriver() { 474 | process_terminate(); 475 | 476 | if ( szPluginPath ) { 477 | free( szPluginPath ); 478 | 479 | szPluginPath = NULL; 480 | } 481 | } 482 | 483 | BOOL VSTDriver::OpenVSTDriver(TCHAR * szPath) { 484 | CloseVSTDriver(); 485 | 486 | load_settings(szPath); 487 | 488 | if ( process_create() ) { 489 | process_write_code( 5 ); 490 | process_write_code( sizeof(uint32_t ) ); 491 | process_write_code( 44100 ); 492 | 493 | uint32_t code = process_read_code(); 494 | if ( code != 0 ) { 495 | process_terminate(); 496 | return FALSE; 497 | } 498 | 499 | process_write_code( 2 ); 500 | process_write_code( blChunk.size() ); 501 | process_write_bytes( blChunk.data(), blChunk.size() ); 502 | 503 | code = process_read_code(); 504 | if ( code != 0 ) { 505 | process_terminate(); 506 | return FALSE; 507 | } 508 | 509 | return TRUE; 510 | } 511 | 512 | return FALSE; 513 | } 514 | 515 | void VSTDriver::ResetDriver() { 516 | process_write_code( 6 ); 517 | uint32_t code = process_read_code(); 518 | if ( code != 0 ) process_terminate(); 519 | } 520 | 521 | void VSTDriver::ProcessMIDIMessage(DWORD dwPort, DWORD dwParam1) { 522 | dwParam1 = ( dwParam1 & 0xFFFFFF ) | ( dwPort << 24 ); 523 | process_write_code( 7 ); 524 | process_write_code( dwParam1 ); 525 | 526 | uint32_t code = process_read_code(); 527 | if ( code != 0 ) process_terminate(); 528 | } 529 | 530 | void VSTDriver::ProcessSysEx(DWORD dwPort, const unsigned char *sysexbuffer,int exlen) { 531 | dwPort = ( dwPort << 24 ) | ( exlen & 0xFFFFFF ); 532 | process_write_code( 8 ); 533 | process_write_code( dwPort ); 534 | process_write_bytes( sysexbuffer, exlen ); 535 | 536 | uint32_t code = process_read_code(); 537 | if ( code != 0 ) process_terminate(); 538 | } 539 | 540 | void VSTDriver::RenderFloat(float * samples, int len, float volume) { 541 | process_write_code( 9 ); 542 | process_write_code( len ); 543 | 544 | uint32_t code = process_read_code(); 545 | if ( code != 0 ) { 546 | process_terminate(); 547 | memset( samples, 0, sizeof(*samples) * len * uNumOutputs ); 548 | return; 549 | } 550 | 551 | while ( len ) { 552 | unsigned len_to_do = len; 553 | if ( len_to_do > 4096 ) len_to_do = 4096; 554 | process_read_bytes( samples, sizeof(*samples) * len_to_do * uNumOutputs ); 555 | for ( unsigned i = 0; i < len_to_do * uNumOutputs; i++ ) samples[ i ] *= volume; 556 | samples += len_to_do * uNumOutputs; 557 | len -= len_to_do; 558 | } 559 | } 560 | 561 | void VSTDriver::Render(short * samples, int len, float volume) 562 | { 563 | float * float_out = (float *) _alloca( 512 * uNumOutputs * sizeof(*float_out) ); 564 | while ( len > 0 ) 565 | { 566 | int len_todo = len > 512 ? 512 : len; 567 | RenderFloat( float_out, len_todo, volume ); 568 | for ( int i = 0; i < len_todo * uNumOutputs; i++ ) 569 | { 570 | int sample = ( float_out[i] * 32768.f ); 571 | if ( ( sample + 0x8000 ) & 0xFFFF0000 ) sample = 0x7FFF ^ (sample >> 31); 572 | samples[0] = sample; 573 | samples++; 574 | } 575 | len -= len_todo; 576 | } 577 | } 578 | -------------------------------------------------------------------------------- /driver/VSTDriver.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 Chris Moeller, Brad Miller 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU Lesser General Public License as published by 5 | * the Free Software Foundation, either version 2.1 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef __VSTDRIVER_H__ 18 | #define __VSTDRIVER_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "../external_packages/aeffect.h" 25 | #include "../external_packages/aeffectx.h" 26 | #include 27 | #include 28 | 29 | class VSTDriver { 30 | private: 31 | TCHAR * szPluginPath; 32 | unsigned uPluginPlatform; 33 | 34 | bool bInitialized; 35 | HANDLE hProcess; 36 | HANDLE hThread; 37 | HANDLE hReadEvent; 38 | HANDLE hChildStd; 39 | 40 | std::vector blChunk; 41 | 42 | unsigned uNumOutputs; 43 | 44 | char * sName; 45 | char * sVendor; 46 | char * sProduct; 47 | uint32_t uVendorVersion; 48 | uint32_t uUniqueId; 49 | 50 | unsigned test_plugin_platform(); 51 | bool connect_pipe( HANDLE hPipe ); 52 | bool process_create(); 53 | void process_terminate(); 54 | bool process_running(); 55 | uint32_t process_read_code(); 56 | void process_read_bytes( void * buffer, uint32_t size ); 57 | uint32_t process_read_bytes_pass( void * buffer, uint32_t size ); 58 | void process_write_code( uint32_t code ); 59 | void process_write_bytes( const void * buffer, uint32_t size ); 60 | 61 | void load_settings(TCHAR * szPath); 62 | 63 | public: 64 | VSTDriver(); 65 | ~VSTDriver(); 66 | void CloseVSTDriver(); 67 | BOOL OpenVSTDriver(TCHAR * szPath = NULL); 68 | void ResetDriver(); 69 | void ProcessMIDIMessage(DWORD dwPort, DWORD dwParam1); 70 | void ProcessSysEx(DWORD dwPort, const unsigned char *sysexbuffer, int exlen); 71 | void Render(short * samples, int len, float volume = 1.0f); 72 | void RenderFloat(float * samples, int len, float volume = 1.0f); 73 | 74 | void getEffectName(std::string & out); 75 | void getVendorString(std::string & out); 76 | void getProductString(std::string & out); 77 | long getVendorVersion(); 78 | long getUniqueID(); 79 | 80 | // configuration 81 | void getChunk(std::vector & out); 82 | void setChunk( const void * in, unsigned size ); 83 | 84 | // editor 85 | bool hasEditor(); 86 | void displayEditorModal(); 87 | }; 88 | 89 | #endif -------------------------------------------------------------------------------- /driver/buildvs.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | SETLOCAL 3 | REM Ensure the environment is set up 4 | if not defined %INCLUDE% GOTO ERROR 5 | REM Workaround to detect x64 or x86 environment 6 | cl 1> NUL 2> tmp.txt 7 | find /C "x64" < tmp.txt > tmp2.txt 8 | SET /p IS64BIT= < tmp2.txt 9 | del tmp.txt 10 | del tmp2.txt 11 | cl /O1 /MT /EHsc /DUNICODE /D_UNICODE /LD /I "..\external_packages" /MP%NUMBER_OF_PROCESSORS% vstmididrv.cpp ..\driver\src\VSTDriver.cpp dsound.cpp sound_out_dsound.cpp sound_out_xaudio2.cpp kernel32.lib user32.lib Shlwapi.lib advapi32.lib winmm.lib Ole32.lib uuid.lib vstmididrv.def 12 | if ERRORLEVEL 1 goto END 13 | REM Move files to the output dir 14 | if "%IS64BIT%" EQU "1" ( 15 | move vstmididrv.dll ..\output\64 16 | ) else ( 17 | move vstmididrv.dll ..\output\ 18 | ) 19 | goto END 20 | :ERROR 21 | echo. 22 | echo This scripts needs to be run from a Visual studio command line 23 | echo (Check Visual Studio tools, Visual studio comand line in the programs menu) 24 | :END 25 | ENDLOCAL -------------------------------------------------------------------------------- /driver/buildvs_debug.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | if "%INCLUDE%" EQU "" GOTO ERROR 3 | @cl /Od /Zi /MTd /EHsc /DUNICODE /D_UNICODE /LDd /I "..\external_packages" vstmididrv.cpp ..\driver\src\VSTDriver.cpp dsound.cpp sound_out_dsound.cpp sound_out_xaudio2.cpp kernel32.lib user32.lib Shlwapi.lib advapi32.lib winmm.lib Ole32.lib uuid.lib vstmididrv.def 4 | goto END 5 | :ERROR 6 | echo. 7 | echo This scripts needs to be run from a Visual studio command line 8 | echo (Check Visual Studio tools, Visual studio comand line in the programs menu) 9 | :END 10 | -------------------------------------------------------------------------------- /driver/ds_stream.h: -------------------------------------------------------------------------------- 1 | #ifndef _DS_STREAM_H_ 2 | #define _DS_STREAM_H_ 3 | 4 | class ds_stream 5 | { 6 | public: 7 | ds_stream() {} 8 | virtual ~ds_stream() {} 9 | 10 | virtual bool write(const void * data,unsigned bytes)=0; 11 | virtual bool is_playing()=0; 12 | virtual double get_latency()=0; 13 | virtual unsigned get_latency_bytes()=0; 14 | virtual unsigned can_write_bytes()=0; 15 | virtual bool force_play()=0; 16 | virtual bool pause(bool status)=0; 17 | virtual bool set_ratio(double ratio)=0; 18 | 19 | //destructor methods 20 | virtual void release()=0; 21 | }; 22 | 23 | struct ds_stream_config 24 | { 25 | unsigned srate; 26 | unsigned short nch,bps; 27 | unsigned buffer_ms; 28 | 29 | ds_stream_config() 30 | : srate(0), nch(0), bps(0), buffer_ms(1000) 31 | {} 32 | }; 33 | 34 | class ds_api 35 | { 36 | protected: 37 | ds_api() {} 38 | virtual ~ds_api() {} 39 | public: 40 | virtual ds_stream * ds_stream_create(const ds_stream_config * cfg)=0; 41 | virtual void set_device(const GUID * id)=0; 42 | 43 | //destructor 44 | virtual void release()=0; 45 | }; 46 | 47 | ds_api * ds_api_create(HWND appwindow); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /driver/dsound.cpp: -------------------------------------------------------------------------------- 1 | #define STRICT 2 | #ifndef _WIN32_WINNT 3 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 4 | #endif 5 | 6 | #include 7 | 8 | #include 9 | 10 | //#define HAVE_KS_HEADERS 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef HAVE_KS_HEADERS 20 | 21 | #include 22 | #include 23 | 24 | #endif 25 | 26 | #include "ds_stream.h" 27 | 28 | class critical_section { 29 | private: 30 | CRITICAL_SECTION sec; 31 | public: 32 | void enter() throw() {EnterCriticalSection(&sec);} 33 | void leave() throw() {LeaveCriticalSection(&sec);} 34 | critical_section() {InitializeCriticalSection(&sec);} 35 | ~critical_section() {DeleteCriticalSection(&sec);} 36 | private: 37 | critical_section(const critical_section&) {} 38 | const critical_section & operator=(const critical_section &) {} 39 | }; 40 | 41 | class c_insync 42 | { 43 | private: 44 | critical_section & m_section; 45 | public: 46 | c_insync(critical_section * p_section) throw() : m_section(*p_section) {m_section.enter();} 47 | c_insync(critical_section & p_section) throw() : m_section(p_section) {m_section.enter();} 48 | ~c_insync() throw() {m_section.leave();} 49 | }; 50 | 51 | #define insync(X) c_insync blah____sync(X) 52 | 53 | namespace 54 | { 55 | class circular_buffer 56 | { 57 | std::vector buffer; 58 | unsigned readptr,writeptr,used,size; 59 | public: 60 | circular_buffer(unsigned p_size) : buffer(p_size), readptr(0), writeptr(0), size(p_size), used(0) {} 61 | unsigned data_available() {return used;} 62 | unsigned free_space() {return size-used;} 63 | bool write(const void * src,unsigned bytes) 64 | { 65 | if (bytes>free_space()) return false; 66 | const char * srcptr = reinterpret_cast(src); 67 | while(bytes) 68 | { 69 | unsigned delta = size - writeptr; 70 | if (delta>bytes) delta = bytes; 71 | memcpy(&buffer.at(0) + writeptr, srcptr, delta); 72 | used += delta; 73 | writeptr = (writeptr + delta) % size; 74 | srcptr += delta; 75 | bytes -= delta; 76 | } 77 | return true; 78 | } 79 | unsigned read(void * dst,unsigned bytes) 80 | { 81 | unsigned done = 0; 82 | char * dstptr = reinterpret_cast(dst); 83 | for(;;) 84 | { 85 | unsigned delta = size - readptr; 86 | if (delta>used) delta=used; 87 | if (delta>bytes) delta=bytes; 88 | if (delta==0) break; 89 | 90 | memcpy(dstptr,&buffer.at(0) + readptr, delta); 91 | dstptr += delta; 92 | done += delta; 93 | readptr = (readptr + delta) % size; 94 | bytes -= delta; 95 | used -= delta; 96 | 97 | } 98 | return done; 99 | } 100 | void reset() 101 | { 102 | readptr=writeptr=used=0; 103 | } 104 | }; 105 | }; 106 | 107 | class ds_stream_i; 108 | 109 | class ds_api_i : public ds_api 110 | { 111 | HANDLE g_thread; 112 | DWORD g_thread_id; 113 | 114 | GUID device; 115 | bool b_have_device; 116 | HWND appwindow; 117 | 118 | static DWORD WINAPI _g_thread_proc(void * param) 119 | { 120 | reinterpret_cast(param)->g_thread_proc(); 121 | return 0; 122 | } 123 | 124 | void g_thread_proc(); 125 | 126 | void g_cleanup_thread(); 127 | void g_thread_sleep() 128 | { 129 | assert(g_is_update_thread()); 130 | SleepEx(10,TRUE); 131 | } 132 | 133 | public: 134 | std::vector g_streams; 135 | IDirectSound * g_p_ds; 136 | 137 | bool g_initialized; 138 | 139 | bool g_is_update_thread() {return g_thread && GetCurrentThreadId() == g_thread_id;} 140 | 141 | bool g_shutting_down; 142 | 143 | critical_section g_sync; 144 | ds_api_i(HWND); 145 | virtual ~ds_api_i(); 146 | virtual ds_stream * ds_stream_create(const ds_stream_config * cfg); 147 | virtual void set_device(const GUID * id); 148 | virtual void release(); 149 | }; 150 | 151 | 152 | 153 | 154 | class ds_stream_i : public ds_stream 155 | { 156 | critical_section & g_sync; 157 | 158 | IDirectSoundBuffer * p_dsb; 159 | unsigned srate; 160 | unsigned short nch,bps; 161 | circular_buffer incoming; 162 | bool b_error; 163 | 164 | int prebuffer_bytes; 165 | int write_min_bytes,write_max_bytes,write_max_ms; 166 | int buffer_size; 167 | int silence_delta; 168 | int silence_bytes; 169 | int last_write; 170 | bool paused,prebuffering,b_force_play; 171 | int latency_bytes; 172 | 173 | bool pause_request; 174 | 175 | double current_time; 176 | 177 | unsigned buffer_ms; 178 | 179 | int ms2bytes(int ms) {return MulDiv(ms,srate,1000)*(bps>>3)*nch;} 180 | int bytes2ms(int bytes) {return MulDiv(bytes,1000,srate*(bps>>3)*nch);} 181 | double bytes2time(unsigned bytes) {return (double)bytes / (double)(srate*(bps>>3)*nch);} 182 | void memsil(void * ptr,int bytes) {memset(ptr,bps==8 ? 0x80 : 0,bytes);} 183 | 184 | void force_play_internal(); 185 | void flush_internal(); 186 | 187 | ds_api_i * api; 188 | bool b_release_requested; 189 | 190 | public: 191 | 192 | bool is_paused() {return paused;} 193 | 194 | ds_stream_i(ds_api_i * p_api,const ds_stream_config * cfg); 195 | virtual ~ds_stream_i(); 196 | 197 | virtual bool write(const void * data,unsigned bytes); 198 | virtual bool is_playing(); 199 | virtual double get_latency(); 200 | virtual unsigned get_latency_bytes(); 201 | virtual unsigned can_write_bytes(); 202 | virtual bool force_play() {insync(g_sync);b_force_play=true;return !b_error;} 203 | 204 | //destructor methods 205 | virtual void release(); 206 | 207 | virtual bool pause(bool status); 208 | 209 | virtual bool set_ratio(double ratio); 210 | 211 | bool update(); 212 | 213 | }; 214 | 215 | void ds_api_i::g_cleanup_thread() 216 | { 217 | CloseHandle(g_thread); 218 | g_thread = 0; 219 | g_thread_id = 0; 220 | for ( unsigned i = 0; i < g_streams.size(); i++ ) delete g_streams[ i ]; 221 | g_streams.clear(); 222 | g_p_ds->Release(); 223 | g_p_ds = 0; 224 | } 225 | 226 | void ds_api_i::g_thread_proc() 227 | { 228 | SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL); 229 | 230 | { 231 | insync(g_sync); 232 | if (!g_initialized) 233 | { 234 | CoInitialize(NULL); 235 | g_initialized = true; 236 | } 237 | g_p_ds = 0; 238 | if (FAILED(CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&g_p_ds))) return; 239 | if (g_p_ds == 0) return; 240 | if (FAILED(g_p_ds->Initialize(b_have_device ? &device : 0))) return; 241 | if (FAILED(g_p_ds->SetCooperativeLevel(appwindow,DSSCL_PRIORITY))) {g_p_ds->Release();g_p_ds=0;return;} 242 | } 243 | 244 | while(!g_shutting_down) 245 | { 246 | bool b_exit = false; 247 | { 248 | insync(g_sync); 249 | 250 | bool b_deleted = false; 251 | { 252 | unsigned n; 253 | for(n=0;nupdate()) n++; 257 | else 258 | { 259 | delete g_streams[ n ]; 260 | g_streams.erase( g_streams.begin() + n ); 261 | b_deleted = true; 262 | } 263 | } 264 | } 265 | 266 | if (b_deleted && g_streams.size()==0) 267 | { 268 | b_exit = true; 269 | g_cleanup_thread(); 270 | } 271 | } 272 | 273 | if (b_exit || g_shutting_down) break; 274 | g_thread_sleep(); 275 | } 276 | } 277 | 278 | ds_stream_i::ds_stream_i(ds_api_i * p_api,const ds_stream_config * cfg) 279 | : srate(cfg->srate), nch(cfg->nch), bps(cfg->bps), incoming(ms2bytes(250)), b_error(false), 280 | api(p_api), g_sync(p_api->g_sync), buffer_ms(cfg->buffer_ms) 281 | { 282 | b_release_requested = false; 283 | prebuffer_bytes = 0; 284 | write_min_bytes = 0; write_max_bytes = 0; write_max_ms = 0; 285 | buffer_size = 0; 286 | silence_delta = 0; 287 | silence_bytes = 0; 288 | last_write = 0; 289 | prebuffering = true; 290 | paused = false; 291 | b_force_play = false; 292 | latency_bytes = 0; 293 | pause_request = false; 294 | current_time = 0; 295 | p_dsb = 0; 296 | } 297 | 298 | ds_stream_i::~ds_stream_i() 299 | { 300 | if (p_dsb) {p_dsb->Stop();p_dsb->Release();p_dsb=0;} 301 | } 302 | 303 | static DWORD get_channel_mask(unsigned nch) 304 | { 305 | #ifdef HAVE_KS_HEADERS 306 | DWORD rv; 307 | switch(nch) 308 | { 309 | default: 310 | rv = 0; 311 | break; 312 | case 1: 313 | rv = KSAUDIO_SPEAKER_MONO; 314 | break; 315 | case 2: 316 | rv = KSAUDIO_SPEAKER_STEREO; 317 | break; 318 | case 4: 319 | rv = KSAUDIO_SPEAKER_QUAD; 320 | break; 321 | case 6: 322 | rv = KSAUDIO_SPEAKER_5POINT1; 323 | break; 324 | } 325 | return rv; 326 | #else 327 | return 0; 328 | #endif 329 | } 330 | 331 | 332 | bool ds_stream_i::update() 333 | { 334 | if (b_release_requested) 335 | return false; 336 | 337 | assert(api->g_p_ds); 338 | if (b_error) return true; 339 | if (p_dsb==0) 340 | { 341 | write_max_ms = buffer_ms; 342 | int buffer_size_ms = write_max_ms > 2000 ? write_max_ms + 2000 : write_max_ms * 2; 343 | int prebuffer_size_ms = write_max_ms/2; 344 | if (prebuffer_size_ms > 10000) prebuffer_size_ms = 10000; 345 | prebuffer_bytes = ms2bytes(prebuffer_size_ms); 346 | 347 | write_min_bytes = ms2bytes(1); 348 | write_max_bytes = ms2bytes(write_max_ms); 349 | 350 | WAVEFORMATEX wfx; 351 | wfx.wFormatTag = bps == 32 ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; 352 | wfx.nChannels = nch; 353 | wfx.nSamplesPerSec = srate; 354 | wfx.nAvgBytesPerSec = ms2bytes(1000); 355 | wfx.nBlockAlign = (bps>>3) * nch; 356 | wfx.wBitsPerSample = bps; 357 | wfx.cbSize = 0; 358 | 359 | DSBUFFERDESC desc; 360 | desc.dwSize = sizeof(desc); 361 | desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_STICKYFOCUS|DSBCAPS_GLOBALFOCUS|DSBCAPS_CTRLFREQUENCY; 362 | desc.dwBufferBytes = buffer_size = ms2bytes(buffer_size_ms); 363 | desc.dwReserved = 0; 364 | desc.lpwfxFormat = &wfx; 365 | 366 | silence_delta = buffer_size / 4; 367 | if (silence_delta > (buffer_size - write_max_bytes)/2) silence_delta = (buffer_size - write_max_bytes)/2; 368 | 369 | if (FAILED(api->g_p_ds->CreateSoundBuffer(&desc,&p_dsb,0))) 370 | { 371 | #ifdef HAVE_KS_HEADERS 372 | WAVEFORMATEXTENSIBLE wfxe; 373 | wfxe.Format=wfx; 374 | wfxe.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; 375 | wfxe.Format.cbSize=22; 376 | wfxe.Samples.wReserved=0; 377 | 378 | wfxe.dwChannelMask=get_channel_mask(nch); 379 | 380 | wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 381 | desc.lpwfxFormat = &wfxe.Format; 382 | if (FAILED(api->g_p_ds->CreateSoundBuffer(&desc,&p_dsb,0))) 383 | #endif 384 | { 385 | b_error = true; 386 | } 387 | } 388 | 389 | if (!b_error) 390 | { 391 | void *p1=0,*p2=0; 392 | DWORD s1=0,s2=0; 393 | if (SUCCEEDED(p_dsb->Lock(0,0,&p1,&s1,&p2,&s2,DSBLOCK_ENTIREBUFFER))) 394 | { 395 | if (p1) memsil(p1,s1); 396 | if (p2) memsil(p2,s2); 397 | p_dsb->Unlock(p1,s1,p2,s2); 398 | } 399 | silence_bytes = buffer_size; 400 | } 401 | 402 | last_write = 0; 403 | prebuffering = true; 404 | } 405 | 406 | if (b_error) return true; 407 | 408 | { 409 | DWORD foo; 410 | p_dsb->GetStatus(&foo); 411 | if (foo&DSBSTATUS_BUFFERLOST) 412 | if (FAILED(p_dsb->Restore())) {b_error = true; return true;} 413 | p_dsb->GetStatus(&foo); 414 | if (!paused && !prebuffering && (foo&(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING))!=(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING)) 415 | p_dsb->Play(0,0,DSBPLAY_LOOPING); 416 | } 417 | 418 | if (!paused) 419 | { 420 | if (p_dsb == 0) 421 | { 422 | latency_bytes = 0; 423 | } 424 | else if (prebuffering) 425 | { 426 | latency_bytes = last_write; 427 | } 428 | else 429 | { 430 | int latency_bytes_old = latency_bytes; 431 | long buffer_position; 432 | if (FAILED(p_dsb->GetCurrentPosition((DWORD*)&buffer_position,0))) buffer_position = 0; 433 | int bytes = last_write - buffer_position; 434 | if (bytes<0) bytes += buffer_size; 435 | if (bytes>buffer_size - (buffer_size - write_max_bytes) / 2) bytes -= buffer_size; 436 | latency_bytes = bytes; 437 | current_time += bytes2time(latency_bytes_old - latency_bytes ); 438 | } 439 | } 440 | 441 | if (b_force_play) 442 | { 443 | force_play_internal(); 444 | b_force_play = false; 445 | } 446 | 447 | 448 | if (pause_request!=paused) 449 | { 450 | if (!prebuffering && p_dsb) 451 | { 452 | if (pause_request) 453 | { 454 | p_dsb->Stop(); 455 | } 456 | else 457 | { 458 | p_dsb->Play(0,0,DSBPLAY_LOOPING); 459 | } 460 | } 461 | paused = pause_request; 462 | } 463 | 464 | if (incoming.data_available()==0) 465 | { 466 | if (!paused && !prebuffering && latency_bytes<=0) 467 | { 468 | flush_internal(); 469 | return true; 470 | } 471 | } 472 | 473 | if (!paused) 474 | 475 | for(;;) 476 | { 477 | int write_start,write_max,write_delta; 478 | 479 | write_start = last_write; 480 | 481 | write_max = latency_bytes>=0 ? write_max_bytes - latency_bytes : write_max_bytes; 482 | 483 | write_delta = 0; 484 | 485 | int chunk_delta = incoming.data_available(); 486 | 487 | if (!prebuffering && latency_bytes write_max) 497 | { 498 | chunk_delta = write_max; 499 | if (chunk_delta<=0) break; 500 | } 501 | 502 | write_delta += chunk_delta; 503 | 504 | { 505 | void *p1=0,*p2=0; 506 | DWORD s1=0,s2=0; 507 | if (chunk_delta > 0) 508 | { 509 | if (SUCCEEDED(p_dsb->Lock(write_start%buffer_size,chunk_delta,&p1,&s1,&p2,&s2,0))) 510 | { 511 | if (p1) 512 | { 513 | incoming.read(p1,s1); 514 | } 515 | if (p2) 516 | { 517 | incoming.read(p2,s2); 518 | } 519 | p_dsb->Unlock(p1,s1,p2,s2); 520 | last_write = (write_start + chunk_delta) % buffer_size; 521 | silence_bytes -= write_delta; 522 | latency_bytes += write_delta; 523 | } 524 | } 525 | 526 | if (silence_bytes < silence_delta) 527 | { 528 | if (SUCCEEDED(p_dsb->Lock((last_write+silence_bytes)%buffer_size,silence_delta,&p1,&s1,&p2,&s2,0))) 529 | { 530 | if (p1) memsil(p1,s1); 531 | if (p2) memsil(p2,s2); 532 | p_dsb->Unlock(p1,s1,p2,s2); 533 | silence_bytes += silence_delta; 534 | } 535 | } 536 | if (prebuffering && last_write>=prebuffer_bytes) force_play_internal(); 537 | } 538 | break; 539 | } 540 | return true; 541 | } 542 | 543 | void ds_stream_i::force_play_internal() 544 | { 545 | if (p_dsb && prebuffering && last_write>0 && !paused) 546 | { 547 | prebuffering = false; 548 | p_dsb->Play(0,0,DSBPLAY_LOOPING); 549 | } 550 | } 551 | 552 | double ds_stream_i::get_latency() 553 | { 554 | return bytes2time(get_latency_bytes()); 555 | } 556 | 557 | unsigned ds_stream_i::get_latency_bytes() 558 | { 559 | insync(g_sync); 560 | int rv = (p_dsb ? latency_bytes : 0) + incoming.data_available(); 561 | if (rv<0) rv=0; 562 | return (unsigned)rv; 563 | } 564 | 565 | bool ds_stream_i::is_playing() 566 | { 567 | insync(g_sync); 568 | return p_dsb && !prebuffering; 569 | } 570 | 571 | bool ds_stream_i::write(const void * data,unsigned bytes) 572 | { 573 | bool rv; 574 | { 575 | insync(g_sync); 576 | rv = incoming.write(data,bytes); 577 | } 578 | return rv; 579 | } 580 | 581 | unsigned ds_stream_i::can_write_bytes() 582 | { 583 | insync(g_sync); 584 | if (b_error) return 0; 585 | else 586 | { 587 | unsigned rv = write_max_bytes - get_latency_bytes(); 588 | if ((signed)rv<0) rv = 0; 589 | unsigned max = incoming.free_space(); 590 | if (rv>max) rv=max; 591 | return rv; 592 | } 593 | } 594 | 595 | void ds_stream_i::flush_internal() 596 | { 597 | if (p_dsb) 598 | { 599 | p_dsb->Stop(); 600 | p_dsb->SetCurrentPosition(0); 601 | { 602 | void *p1=0,*p2=0; 603 | DWORD s1=0,s2=0; 604 | if (SUCCEEDED(p_dsb->Lock(0,0,&p1,&s1,&p2,&s2,DSBLOCK_ENTIREBUFFER))) 605 | { 606 | if (p1) memsil(p1,s1); 607 | if (p2) memsil(p2,s2); 608 | p_dsb->Unlock(p1,s1,p2,s2); 609 | } 610 | silence_bytes = buffer_size; 611 | } 612 | prebuffering = true; 613 | } 614 | last_write = 0; 615 | latency_bytes = 0; 616 | current_time = 0; 617 | incoming.reset(); 618 | } 619 | 620 | 621 | bool ds_stream_i::pause(bool status) 622 | { 623 | insync(g_sync); 624 | if (b_error) return false; 625 | else 626 | { 627 | pause_request = !!status; 628 | return true; 629 | } 630 | } 631 | 632 | 633 | bool ds_stream_i::set_ratio(double ratio) 634 | { 635 | insync(g_sync); 636 | if (b_error) return false; 637 | else 638 | { 639 | if ( FAILED( p_dsb->SetFrequency( static_cast(srate * ratio) ) ) ) return false; 640 | else return true; 641 | } 642 | } 643 | 644 | 645 | 646 | 647 | 648 | ds_api * ds_api_create(HWND appwindow) {return appwindow ? (ds_api*)(new ds_api_i(appwindow)) : 0;} 649 | 650 | 651 | void ds_api_i::set_device(const GUID * id) 652 | { 653 | insync(g_sync); 654 | if (id) {b_have_device = true; device = *id;} 655 | else b_have_device = false; 656 | } 657 | 658 | ds_stream * ds_api_i::ds_stream_create(const ds_stream_config * cfg) 659 | { 660 | ds_stream_i * ptr = new ds_stream_i(this,cfg); 661 | if (ptr) 662 | { 663 | insync(g_sync); 664 | g_streams.push_back( ptr ); 665 | if (g_thread==0) 666 | { 667 | g_thread = CreateThread(0,0,_g_thread_proc,reinterpret_cast(this),0,&g_thread_id); 668 | } 669 | } 670 | return ptr; 671 | } 672 | 673 | ds_api_i::ds_api_i(HWND p_appwindow) : appwindow(p_appwindow) 674 | { 675 | b_have_device = false; 676 | g_p_ds = 0; 677 | g_thread = 0; 678 | g_thread_id = 0; 679 | g_shutting_down = false; 680 | g_initialized = false; 681 | } 682 | 683 | ds_api_i::~ds_api_i() 684 | { 685 | HANDLE blah = 0; 686 | { 687 | insync(g_sync); 688 | g_shutting_down = true; 689 | if (g_thread) 690 | { 691 | HANDLE h_process = GetCurrentProcess(); 692 | DuplicateHandle(h_process,g_thread,h_process,&blah,0,FALSE,DUPLICATE_SAME_ACCESS); 693 | } 694 | } 695 | if (blah) 696 | { 697 | WaitForSingleObject(blah,INFINITE); 698 | CloseHandle(blah); 699 | } 700 | 701 | { 702 | insync(g_sync); 703 | for ( unsigned i = 0; i < g_streams.size(); i++ ) delete g_streams[ i ]; 704 | g_streams.clear(); 705 | } 706 | 707 | if (g_initialized) CoUninitialize(); 708 | } 709 | 710 | void ds_api_i::release() 711 | { 712 | delete this; 713 | } 714 | 715 | void ds_stream_i::release() 716 | { 717 | insync(g_sync); 718 | b_release_requested = true; 719 | } -------------------------------------------------------------------------------- /driver/mmddk.h: -------------------------------------------------------------------------------- 1 | /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 2 | 3 | /***************************************************************************** 4 | * Copyright 1998, Luiz Otavio L. Zorzella 5 | * 1999, Eric Pouech 6 | * 7 | * Purpose: multimedia declarations (external to WINMM & MMSYSTEM DLLs 8 | * for other DLLs (MCI, drivers...)) 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 2.1 of the License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 | * 24 | ***************************************************************************** 25 | */ 26 | #ifndef __MMDDK_H 27 | #define __MMDDK_H 28 | 29 | #include 30 | #include 31 | 32 | /* Maxium drivers */ 33 | #define MAXWAVEDRIVERS 10 34 | 35 | #define MAX_MIDIINDRV (16) 36 | /* For now I'm making 16 the maximum number of midi devices one can 37 | * have. This should be more than enough for everybody. But as a purist, 38 | * I intend to make it unbounded in the future, as soon as I figure 39 | * a good way to do so. 40 | */ 41 | #define MAX_MIDIOUTDRV (16) 42 | 43 | /* ================================== 44 | * Multimedia DDK compatible part 45 | * ================================== */ 46 | 47 | #include 48 | 49 | #define DRVM_INIT 100 50 | #define DRVM_EXIT 101 51 | #define DRVM_DISABLE 102 52 | #define DRVM_ENABLE 103 53 | 54 | /* messages that have IOCTL format 55 | * dw1 = NULL or handle 56 | * dw2 = NULL or ptr to DRVM_IOCTL_DATA 57 | * return is MMRESULT 58 | */ 59 | #define DRVM_IOCTL 0x100 60 | #define DRVM_ADD_THRU (DRVM_IOCTL+1) 61 | #define DRVM_REMOVE_THRU (DRVM_IOCTL+2) 62 | #define DRVM_IOCTL_LAST (DRVM_IOCTL+5) 63 | typedef struct { 64 | DWORD dwSize; /* size of this structure */ 65 | DWORD dwCmd; /* IOCTL command code, 0x80000000 and above reserved for system */ 66 | } DRVM_IOCTL_DATA, *LPDRVM_IOCTL_DATA; 67 | 68 | /* command code ranges for dwCmd field of DRVM_IOCTL message 69 | * - codes from 0 to 0x7FFFFFFF are user defined 70 | * - codes from 0x80000000 to 0xFFFFFFFF are reserved for future definition by microsoft 71 | */ 72 | #define DRVM_IOCTL_CMD_USER 0x00000000L 73 | #define DRVM_IOCTL_CMD_SYSTEM 0x80000000L 74 | 75 | #define DRVM_MAPPER 0x2000 76 | #define DRVM_USER 0x4000 77 | #define DRVM_MAPPER_STATUS (DRVM_MAPPER+0) 78 | #define DRVM_MAPPER_RECONFIGURE (DRVM_MAPPER+1) 79 | #define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER+21) 80 | #define DRVM_MAPPER_CONSOLEVOICECOM_GET (DRVM_MAPPER+23) 81 | 82 | #define DRV_QUERYDRVENTRY (DRV_RESERVED + 1) 83 | #define DRV_QUERYDEVNODE (DRV_RESERVED + 2) 84 | #define DRV_QUERYNAME (DRV_RESERVED + 3) 85 | #define DRV_QUERYDRIVERIDS (DRV_RESERVED + 4) 86 | #define DRV_QUERYMAPPABLE (DRV_RESERVED + 5) 87 | #define DRV_QUERYMODULE (DRV_RESERVED + 9) 88 | #define DRV_PNPINSTALL (DRV_RESERVED + 11) 89 | #define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) 90 | #define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) 91 | #define DRV_QUERYSTRINGID (DRV_RESERVED + 14) 92 | #define DRV_QUERYSTRINGIDSIZE (DRV_RESERVED + 15) 93 | #define DRV_QUERYIDFROMSTRINGID (DRV_RESERVED + 16) 94 | #ifdef __WINESRC__ 95 | #define DRV_QUERYDSOUNDIFACE (DRV_RESERVED + 20) 96 | #define DRV_QUERYDSOUNDDESC (DRV_RESERVED + 21) 97 | #define DRV_QUERYDSOUNDGUID (DRV_RESERVED + 22) 98 | #endif 99 | 100 | #define WODM_INIT DRVM_INIT 101 | #define WODM_GETNUMDEVS 3 102 | #define WODM_GETDEVCAPS 4 103 | #define WODM_OPEN 5 104 | #define WODM_CLOSE 6 105 | #define WODM_PREPARE 7 106 | #define WODM_UNPREPARE 8 107 | #define WODM_WRITE 9 108 | #define WODM_PAUSE 10 109 | #define WODM_RESTART 11 110 | #define WODM_RESET 12 111 | #define WODM_GETPOS 13 112 | #define WODM_GETPITCH 14 113 | #define WODM_SETPITCH 15 114 | #define WODM_GETVOLUME 16 115 | #define WODM_SETVOLUME 17 116 | #define WODM_GETPLAYBACKRATE 18 117 | #define WODM_SETPLAYBACKRATE 19 118 | #define WODM_BREAKLOOP 20 119 | #define WODM_PREFERRED 21 120 | 121 | #define WODM_MAPPER_STATUS (DRVM_MAPPER_STATUS + 0) 122 | #define WAVEOUT_MAPPER_STATUS_DEVICE 0 123 | #define WAVEOUT_MAPPER_STATUS_MAPPED 1 124 | #define WAVEOUT_MAPPER_STATUS_FORMAT 2 125 | 126 | #define WODM_BUSY 21 127 | 128 | #define WIDM_INIT DRVM_INIT 129 | #define WIDM_GETNUMDEVS 50 130 | #define WIDM_GETDEVCAPS 51 131 | #define WIDM_OPEN 52 132 | #define WIDM_CLOSE 53 133 | #define WIDM_PREPARE 54 134 | #define WIDM_UNPREPARE 55 135 | #define WIDM_ADDBUFFER 56 136 | #define WIDM_START 57 137 | #define WIDM_STOP 58 138 | #define WIDM_RESET 59 139 | #define WIDM_GETPOS 60 140 | #define WIDM_PREFERRED 61 141 | #define WIDM_MAPPER_STATUS (DRVM_MAPPER_STATUS + 0) 142 | #define WAVEIN_MAPPER_STATUS_DEVICE 0 143 | #define WAVEIN_MAPPER_STATUS_MAPPED 1 144 | #define WAVEIN_MAPPER_STATUS_FORMAT 2 145 | 146 | #define MODM_INIT DRVM_INIT 147 | #define MODM_GETNUMDEVS 1 148 | #define MODM_GETDEVCAPS 2 149 | #define MODM_OPEN 3 150 | #define MODM_CLOSE 4 151 | #define MODM_PREPARE 5 152 | #define MODM_UNPREPARE 6 153 | #define MODM_DATA 7 154 | #define MODM_LONGDATA 8 155 | #define MODM_RESET 9 156 | #define MODM_GETVOLUME 10 157 | #define MODM_SETVOLUME 11 158 | #define MODM_CACHEPATCHES 12 159 | #define MODM_CACHEDRUMPATCHES 13 160 | 161 | #define MIDM_INIT DRVM_INIT 162 | #define MIDM_GETNUMDEVS 53 163 | #define MIDM_GETDEVCAPS 54 164 | #define MIDM_OPEN 55 165 | #define MIDM_CLOSE 56 166 | #define MIDM_PREPARE 57 167 | #define MIDM_UNPREPARE 58 168 | #define MIDM_ADDBUFFER 59 169 | #define MIDM_START 60 170 | #define MIDM_STOP 61 171 | #define MIDM_RESET 62 172 | 173 | 174 | #define AUXM_INIT DRVM_INIT 175 | #define AUXDM_GETNUMDEVS 3 176 | #define AUXDM_GETDEVCAPS 4 177 | #define AUXDM_GETVOLUME 5 178 | #define AUXDM_SETVOLUME 6 179 | 180 | #define MXDM_INIT DRVM_INIT 181 | #define MXDM_USER DRVM_USER 182 | #define MXDM_MAPPER DRVM_MAPPER 183 | 184 | #define MXDM_GETNUMDEVS 1 185 | #define MXDM_GETDEVCAPS 2 186 | #define MXDM_OPEN 3 187 | #define MXDM_CLOSE 4 188 | #define MXDM_GETLINEINFO 5 189 | #define MXDM_GETLINECONTROLS 6 190 | #define MXDM_GETCONTROLDETAILS 7 191 | #define MXDM_SETCONTROLDETAILS 8 192 | 193 | /* pre-defined joystick types */ 194 | #define JOY_HW_NONE 0 195 | #define JOY_HW_CUSTOM 1 196 | #define JOY_HW_2A_2B_GENERIC 2 197 | #define JOY_HW_2A_4B_GENERIC 3 198 | #define JOY_HW_2B_GAMEPAD 4 199 | #define JOY_HW_2B_FLIGHTYOKE 5 200 | #define JOY_HW_2B_FLIGHTYOKETHROTTLE 6 201 | #define JOY_HW_3A_2B_GENERIC 7 202 | #define JOY_HW_3A_4B_GENERIC 8 203 | #define JOY_HW_4B_GAMEPAD 9 204 | #define JOY_HW_4B_FLIGHTYOKE 10 205 | #define JOY_HW_4B_FLIGHTYOKETHROTTLE 11 206 | #define JOY_HW_LASTENTRY 12 207 | 208 | /* calibration flags */ 209 | #define JOY_ISCAL_XY 0x00000001l /* XY are calibrated */ 210 | #define JOY_ISCAL_Z 0x00000002l /* Z is calibrated */ 211 | #define JOY_ISCAL_R 0x00000004l /* R is calibrated */ 212 | #define JOY_ISCAL_U 0x00000008l /* U is calibrated */ 213 | #define JOY_ISCAL_V 0x00000010l /* V is calibrated */ 214 | #define JOY_ISCAL_POV 0x00000020l /* POV is calibrated */ 215 | 216 | /* point of view constants */ 217 | #define JOY_POV_NUMDIRS 4 218 | #define JOY_POVVAL_FORWARD 0 219 | #define JOY_POVVAL_BACKWARD 1 220 | #define JOY_POVVAL_LEFT 2 221 | #define JOY_POVVAL_RIGHT 3 222 | 223 | /* Specific settings for joystick hardware */ 224 | #define JOY_HWS_HASZ 0x00000001l /* has Z info? */ 225 | #define JOY_HWS_HASPOV 0x00000002l /* point of view hat present */ 226 | #define JOY_HWS_POVISBUTTONCOMBOS 0x00000004l /* pov done through combo of buttons */ 227 | #define JOY_HWS_POVISPOLL 0x00000008l /* pov done through polling */ 228 | #define JOY_HWS_ISYOKE 0x00000010l /* joystick is a flight yoke */ 229 | #define JOY_HWS_ISGAMEPAD 0x00000020l /* joystick is a game pad */ 230 | #define JOY_HWS_ISCARCTRL 0x00000040l /* joystick is a car controller */ 231 | /* X defaults to J1 X axis */ 232 | #define JOY_HWS_XISJ1Y 0x00000080l /* X is on J1 Y axis */ 233 | #define JOY_HWS_XISJ2X 0x00000100l /* X is on J2 X axis */ 234 | #define JOY_HWS_XISJ2Y 0x00000200l /* X is on J2 Y axis */ 235 | /* Y defaults to J1 Y axis */ 236 | #define JOY_HWS_YISJ1X 0x00000400l /* Y is on J1 X axis */ 237 | #define JOY_HWS_YISJ2X 0x00000800l /* Y is on J2 X axis */ 238 | #define JOY_HWS_YISJ2Y 0x00001000l /* Y is on J2 Y axis */ 239 | /* Z defaults to J2 Y axis */ 240 | #define JOY_HWS_ZISJ1X 0x00002000l /* Z is on J1 X axis */ 241 | #define JOY_HWS_ZISJ1Y 0x00004000l /* Z is on J1 Y axis */ 242 | #define JOY_HWS_ZISJ2X 0x00008000l /* Z is on J2 X axis */ 243 | /* POV defaults to J2 Y axis, if it is not button based */ 244 | #define JOY_HWS_POVISJ1X 0x00010000l /* pov done through J1 X axis */ 245 | #define JOY_HWS_POVISJ1Y 0x00020000l /* pov done through J1 Y axis */ 246 | #define JOY_HWS_POVISJ2X 0x00040000l /* pov done through J2 X axis */ 247 | /* R defaults to J2 X axis */ 248 | #define JOY_HWS_HASR 0x00080000l /* has R (4th axis) info */ 249 | #define JOY_HWS_RISJ1X 0x00100000l /* R done through J1 X axis */ 250 | #define JOY_HWS_RISJ1Y 0x00200000l /* R done through J1 Y axis */ 251 | #define JOY_HWS_RISJ2Y 0x00400000l /* R done through J2 X axis */ 252 | /* U & V for future hardware */ 253 | #define JOY_HWS_HASU 0x00800000l /* has U (5th axis) info */ 254 | #define JOY_HWS_HASV 0x01000000l /* has V (6th axis) info */ 255 | 256 | /* Usage settings */ 257 | #define JOY_US_HASRUDDER 0x00000001l /* joystick configured with rudder */ 258 | #define JOY_US_PRESENT 0x00000002l /* is joystick actually present? */ 259 | #define JOY_US_ISOEM 0x00000004l /* joystick is an OEM defined type */ 260 | 261 | 262 | /* struct for storing x,y, z, and rudder values */ 263 | typedef struct joypos_tag { 264 | DWORD dwX; 265 | DWORD dwY; 266 | DWORD dwZ; 267 | DWORD dwR; 268 | DWORD dwU; 269 | DWORD dwV; 270 | } JOYPOS, *LPJOYPOS; 271 | 272 | /* struct for storing ranges */ 273 | typedef struct joyrange_tag { 274 | JOYPOS jpMin; 275 | JOYPOS jpMax; 276 | JOYPOS jpCenter; 277 | } JOYRANGE,*LPJOYRANGE; 278 | 279 | typedef struct joyreguservalues_tag { 280 | DWORD dwTimeOut; /* value at which to timeout joystick polling */ 281 | JOYRANGE jrvRanges; /* range of values app wants returned for axes */ 282 | JOYPOS jpDeadZone; /* area around center to be considered 283 | as "dead". specified as a percentage 284 | (0-100). Only X & Y handled by system driver */ 285 | } JOYREGUSERVALUES, *LPJOYREGUSERVALUES; 286 | 287 | typedef struct joyreghwsettings_tag { 288 | DWORD dwFlags; 289 | DWORD dwNumButtons; /* number of buttons */ 290 | } JOYREGHWSETTINGS, *LPJOYHWSETTINGS; 291 | 292 | /* range of values returned by the hardware (filled in by calibration) */ 293 | typedef struct joyreghwvalues_tag { 294 | JOYRANGE jrvHardware; /* values returned by hardware */ 295 | DWORD dwPOVValues[JOY_POV_NUMDIRS];/* POV values returned by hardware */ 296 | DWORD dwCalFlags; /* what has been calibrated */ 297 | } JOYREGHWVALUES, *LPJOYREGHWVALUES; 298 | 299 | /* hardware configuration */ 300 | typedef struct joyreghwconfig_tag { 301 | JOYREGHWSETTINGS hws; /* hardware settings */ 302 | DWORD dwUsageSettings;/* usage settings */ 303 | JOYREGHWVALUES hwv; /* values returned by hardware */ 304 | DWORD dwType; /* type of joystick */ 305 | DWORD dwReserved; /* reserved for OEM drivers */ 306 | } JOYREGHWCONFIG, *LPJOYREGHWCONFIG; 307 | 308 | /* joystick calibration info structure */ 309 | typedef struct joycalibrate_tag { 310 | UINT wXbase; 311 | UINT wXdelta; 312 | UINT wYbase; 313 | UINT wYdelta; 314 | UINT wZbase; 315 | UINT wZdelta; 316 | } JOYCALIBRATE; 317 | typedef JOYCALIBRATE *LPJOYCALIBRATE; 318 | 319 | /* prototype for joystick message function */ 320 | typedef UINT (CALLBACK * JOYDEVMSGPROC)(DWORD dwID, UINT uMessage, LPARAM lParam1, LPARAM lParam2); 321 | typedef JOYDEVMSGPROC *LPJOYDEVMSGPROC; 322 | 323 | /* messages sent to joystick driver's DriverProc() function */ 324 | #define JDD_GETNUMDEVS (DRV_RESERVED + 0x0001) 325 | #define JDD_GETDEVCAPS (DRV_RESERVED + 0x0002) 326 | #define JDD_GETPOS (DRV_RESERVED + 0x0101) 327 | #define JDD_SETCALIBRATION (DRV_RESERVED + 0x0102) 328 | #define JDD_CONFIGCHANGED (DRV_RESERVED + 0x0103) 329 | #define JDD_GETPOSEX (DRV_RESERVED + 0x0104) 330 | 331 | #define MCI_MAX_DEVICE_TYPE_LENGTH 80 332 | 333 | #define MCI_FALSE (MCI_STRING_OFFSET + 19) 334 | #define MCI_TRUE (MCI_STRING_OFFSET + 20) 335 | 336 | #define MCI_FORMAT_RETURN_BASE MCI_FORMAT_MILLISECONDS_S 337 | #define MCI_FORMAT_MILLISECONDS_S (MCI_STRING_OFFSET + 21) 338 | #define MCI_FORMAT_HMS_S (MCI_STRING_OFFSET + 22) 339 | #define MCI_FORMAT_MSF_S (MCI_STRING_OFFSET + 23) 340 | #define MCI_FORMAT_FRAMES_S (MCI_STRING_OFFSET + 24) 341 | #define MCI_FORMAT_SMPTE_24_S (MCI_STRING_OFFSET + 25) 342 | #define MCI_FORMAT_SMPTE_25_S (MCI_STRING_OFFSET + 26) 343 | #define MCI_FORMAT_SMPTE_30_S (MCI_STRING_OFFSET + 27) 344 | #define MCI_FORMAT_SMPTE_30DROP_S (MCI_STRING_OFFSET + 28) 345 | #define MCI_FORMAT_BYTES_S (MCI_STRING_OFFSET + 29) 346 | #define MCI_FORMAT_SAMPLES_S (MCI_STRING_OFFSET + 30) 347 | #define MCI_FORMAT_TMSF_S (MCI_STRING_OFFSET + 31) 348 | 349 | #define MCI_VD_FORMAT_TRACK_S (MCI_VD_OFFSET + 5) 350 | 351 | #define WAVE_FORMAT_PCM_S (MCI_WAVE_OFFSET + 0) 352 | #define WAVE_MAPPER_S (MCI_WAVE_OFFSET + 1) 353 | 354 | #define MCI_SEQ_MAPPER_S (MCI_SEQ_OFFSET + 5) 355 | #define MCI_SEQ_FILE_S (MCI_SEQ_OFFSET + 6) 356 | #define MCI_SEQ_MIDI_S (MCI_SEQ_OFFSET + 7) 357 | #define MCI_SEQ_SMPTE_S (MCI_SEQ_OFFSET + 8) 358 | #define MCI_SEQ_FORMAT_SONGPTR_S (MCI_SEQ_OFFSET + 9) 359 | #define MCI_SEQ_NONE_S (MCI_SEQ_OFFSET + 10) 360 | #define MIDIMAPPER_S (MCI_SEQ_OFFSET + 11) 361 | 362 | #define MCI_RESOURCE_RETURNED 0x00010000 /* resource ID */ 363 | #define MCI_COLONIZED3_RETURN 0x00020000 /* colonized ID, 3 bytes data */ 364 | #define MCI_COLONIZED4_RETURN 0x00040000 /* colonized ID, 4 bytes data */ 365 | #define MCI_INTEGER_RETURNED 0x00080000 /* integer conversion needed */ 366 | #define MCI_RESOURCE_DRIVER 0x00100000 /* driver owns returned resource */ 367 | 368 | #define MCI_NO_COMMAND_TABLE 0xFFFF 369 | 370 | #define MCI_COMMAND_HEAD 0 371 | #define MCI_STRING 1 372 | #define MCI_INTEGER 2 373 | #define MCI_END_COMMAND 3 374 | #define MCI_RETURN 4 375 | #define MCI_FLAG 5 376 | #define MCI_END_COMMAND_LIST 6 377 | #define MCI_RECT 7 378 | #define MCI_CONSTANT 8 379 | #define MCI_END_CONSTANT 9 380 | 381 | #define MAKEMCIRESOURCE(wRet, wRes) MAKELRESULT((wRet), (wRes)) 382 | 383 | typedef struct { 384 | DWORD dwCallback; 385 | DWORD dwInstance; 386 | HMIDIOUT hMidi; 387 | DWORD dwFlags; 388 | } PORTALLOC, *LPPORTALLOC; 389 | 390 | typedef struct { 391 | HWAVE hWave; 392 | LPWAVEFORMATEX lpFormat; 393 | DWORD dwCallback; 394 | DWORD dwInstance; 395 | UINT uMappedDeviceID; 396 | DWORD dnDevNode; 397 | } WAVEOPENDESC, *LPWAVEOPENDESC; 398 | 399 | typedef struct { 400 | DWORD dwStreamID; 401 | WORD wDeviceID; 402 | } MIDIOPENSTRMID; 403 | 404 | typedef struct { 405 | HMIDI hMidi; 406 | DWORD dwCallback; 407 | DWORD dwInstance; 408 | DWORD dnDevNode; 409 | DWORD cIds; 410 | MIDIOPENSTRMID rgIds; 411 | } MIDIOPENDESC, *LPMIDIOPENDESC; 412 | 413 | typedef struct tMIXEROPENDESC 414 | { 415 | HMIXEROBJ hmx; 416 | LPVOID pReserved0; 417 | DWORD dwCallback; 418 | DWORD dwInstance; 419 | } MIXEROPENDESC, *LPMIXEROPENDESC; 420 | 421 | typedef struct { 422 | UINT wDeviceID; /* device ID */ 423 | LPSTR lpstrParams; /* parameter string for entry in SYSTEM.INI */ 424 | UINT wCustomCommandTable; /* custom command table (0xFFFF if none) * filled in by the driver */ 425 | UINT wType; /* driver type (filled in by the driver) */ 426 | } MCI_OPEN_DRIVER_PARMSA, *LPMCI_OPEN_DRIVER_PARMSA; 427 | 428 | typedef struct { 429 | UINT wDeviceID; /* device ID */ 430 | LPWSTR lpstrParams; /* parameter string for entry in SYSTEM.INI */ 431 | UINT wCustomCommandTable; /* custom command table (0xFFFF if none) * filled in by the driver */ 432 | UINT wType; /* driver type (filled in by the driver) */ 433 | } MCI_OPEN_DRIVER_PARMSW, *LPMCI_OPEN_DRIVER_PARMSW; 434 | 435 | DWORD WINAPI mciGetDriverData(UINT uDeviceID); 436 | BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD dwData); 437 | UINT WINAPI mciDriverYield(UINT uDeviceID); 438 | BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID, 439 | UINT uStatus); 440 | UINT WINAPI mciLoadCommandResource(HINSTANCE hInstance, 441 | LPCWSTR lpResName, UINT uType); 442 | BOOL WINAPI mciFreeCommandResource(UINT uTable); 443 | 444 | #define DCB_NULL 0x0000 445 | #define DCB_WINDOW 0x0001 /* dwCallback is a HWND */ 446 | #define DCB_TASK 0x0002 /* dwCallback is a HTASK */ 447 | #define DCB_FUNCTION 0x0003 /* dwCallback is a FARPROC */ 448 | #define DCB_EVENT 0x0005 /* dwCallback is an EVENT Handler */ 449 | #define DCB_TYPEMASK 0x0007 450 | #define DCB_NOSWITCH 0x0008 /* don't switch stacks for callback */ 451 | 452 | BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev, 453 | UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); 454 | 455 | typedef void (*LPTASKCALLBACK)(DWORD dwInst); 456 | 457 | #define TASKERR_NOTASKSUPPORT 1 458 | #define TASKERR_OUTOFMEMORY 2 459 | MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK, HANDLE*, DWORD); 460 | void WINAPI mmTaskBlock(HANDLE); 461 | BOOL WINAPI mmTaskSignal(HANDLE); 462 | void WINAPI mmTaskYield(void); 463 | HANDLE WINAPI mmGetCurrentTask(void); 464 | 465 | 466 | #define WAVE_DIRECTSOUND 0x0080 467 | 468 | 469 | #include 470 | 471 | #endif /* __MMDDK_H */ 472 | -------------------------------------------------------------------------------- /driver/sound_out.h: -------------------------------------------------------------------------------- 1 | #ifndef _sound_out_h_ 2 | #define _sound_out_h_ 3 | 4 | class sound_out 5 | { 6 | public: 7 | virtual ~sound_out() {} 8 | 9 | virtual const char* open( void * hwnd, unsigned sample_rate, unsigned short nch, bool floating_point, unsigned max_samples_per_frame, unsigned num_frames ) = 0; 10 | 11 | virtual const char* write_frame( void * buffer, unsigned num_samples, bool wait = true ) = 0; 12 | 13 | virtual const char* set_ratio( double ratio ) = 0; 14 | 15 | virtual const char* pause( bool pausing ) = 0; 16 | 17 | virtual double buffered() = 0; 18 | }; 19 | 20 | sound_out * create_sound_out_ds(); 21 | sound_out * create_sound_out_xaudio2(); 22 | 23 | #endif -------------------------------------------------------------------------------- /driver/sound_out_dsound.cpp: -------------------------------------------------------------------------------- 1 | #define STRICT 2 | #ifndef _WIN32_WINNT 3 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 4 | #endif 5 | 6 | #include 7 | 8 | #include "sound_out.h" 9 | 10 | #include "ds_stream.h" 11 | 12 | class sound_out_i_dsound : public sound_out 13 | { 14 | ds_api * p_api; 15 | ds_stream * p_stream; 16 | 17 | bool paused; 18 | 19 | unsigned sample_rate, max_samples_per_frame, num_frames, bytes_per_sample, buffer_size_bytes, last_write; 20 | unsigned short nch; 21 | 22 | public: 23 | sound_out_i_dsound() 24 | { 25 | p_api = 0; 26 | p_stream = 0; 27 | paused = false; 28 | } 29 | 30 | virtual ~sound_out_i_dsound() 31 | { 32 | close(); 33 | } 34 | 35 | virtual const char* open( void * hwnd, unsigned sample_rate, unsigned short nch, bool floating_point, unsigned max_samples_per_frame, unsigned num_frames ) 36 | { 37 | p_api = ds_api_create( (HWND) hwnd ); 38 | if ( !p_api ) 39 | { 40 | return "Initializing DirectSound"; 41 | } 42 | 43 | this->sample_rate = sample_rate; 44 | this->nch = nch; 45 | this->max_samples_per_frame = max_samples_per_frame; 46 | this->num_frames = num_frames; 47 | bytes_per_sample = floating_point ? 4 : 2; 48 | 49 | ds_stream_config cfg; 50 | cfg.srate = sample_rate; 51 | cfg.nch = nch; 52 | cfg.bps = floating_point ? 32 : 16; 53 | cfg.buffer_ms = MulDiv( max_samples_per_frame / nch * num_frames, 1000, sample_rate ); 54 | 55 | p_stream = p_api->ds_stream_create( &cfg ); 56 | if ( !p_stream ) 57 | { 58 | return "Creating DirectSound stream object"; 59 | } 60 | 61 | return NULL; 62 | } 63 | 64 | void close() 65 | { 66 | if ( p_stream ) 67 | { 68 | p_stream->release(); 69 | p_stream = 0; 70 | } 71 | 72 | if ( p_api ) 73 | { 74 | p_api->release(); 75 | p_api = 0; 76 | } 77 | } 78 | 79 | virtual const char* write_frame( void * buffer, unsigned num_samples, bool wait ) 80 | { 81 | if ( paused ) 82 | { 83 | if ( wait ) Sleep( MulDiv( num_samples / nch, 1000, sample_rate ) ); 84 | return 0; 85 | } 86 | 87 | unsigned int buffer_size_write = num_samples * bytes_per_sample; 88 | 89 | if ( wait ) 90 | { 91 | while ( p_stream->can_write_bytes() < buffer_size_write ) Sleep( 1 ); 92 | } 93 | 94 | p_stream->write( buffer, buffer_size_write ); 95 | 96 | return 0; 97 | } 98 | 99 | virtual const char* set_ratio( double ratio ) 100 | { 101 | if ( !p_stream->set_ratio( ratio ) ) return "setting ratio"; 102 | return 0; 103 | } 104 | 105 | virtual const char* pause( bool pausing ) 106 | { 107 | p_stream->pause( paused = pausing ); 108 | 109 | return 0; 110 | } 111 | 112 | virtual double buffered() 113 | { 114 | unsigned bytes = p_stream->get_latency_bytes(); 115 | unsigned write_max_bytes = max_samples_per_frame * 2; 116 | return double( bytes ) / double( write_max_bytes ); 117 | } 118 | }; 119 | 120 | sound_out * create_sound_out_ds() 121 | { 122 | return new sound_out_i_dsound; 123 | } -------------------------------------------------------------------------------- /driver/sound_out_xaudio2.cpp: -------------------------------------------------------------------------------- 1 | #define STRICT 2 | #ifndef _WIN32_WINNT 3 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 4 | #endif 5 | 6 | #include "sound_out.h" 7 | 8 | //#define HAVE_KS_HEADERS 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #ifdef HAVE_KS_HEADERS 17 | #include 18 | #include 19 | #endif 20 | 21 | 22 | #pragma comment ( lib, "winmm.lib" ) 23 | 24 | class sound_out_i_xaudio2; 25 | 26 | void xaudio2_device_changed( sound_out_i_xaudio2 * ); 27 | 28 | class XAudio2_Device_Notifier : public IMMNotificationClient 29 | { 30 | volatile LONG registered; 31 | IMMDeviceEnumerator *pEnumerator; 32 | 33 | CRITICAL_SECTION lock; 34 | std::vector instances; 35 | 36 | public: 37 | XAudio2_Device_Notifier() : registered( 0 ) 38 | { 39 | InitializeCriticalSection( &lock ); 40 | } 41 | ~XAudio2_Device_Notifier() 42 | { 43 | DeleteCriticalSection( &lock ); 44 | } 45 | 46 | ULONG STDMETHODCALLTYPE AddRef() 47 | { 48 | return 1; 49 | } 50 | 51 | ULONG STDMETHODCALLTYPE Release() 52 | { 53 | return 1; 54 | } 55 | 56 | HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, VOID **ppvInterface ) 57 | { 58 | if (IID_IUnknown == riid) 59 | { 60 | *ppvInterface = (IUnknown*)this; 61 | } 62 | else if (__uuidof(IMMNotificationClient) == riid) 63 | { 64 | *ppvInterface = (IMMNotificationClient*)this; 65 | } 66 | else 67 | { 68 | *ppvInterface = NULL; 69 | return E_NOINTERFACE; 70 | } 71 | return S_OK; 72 | } 73 | 74 | HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId ) 75 | { 76 | if ( flow == eRender ) 77 | { 78 | EnterCriticalSection( &lock ); 79 | for ( std::vector::iterator it = instances.begin(); it < instances.end(); ++it ) 80 | { 81 | xaudio2_device_changed( *it ); 82 | } 83 | LeaveCriticalSection( &lock ); 84 | } 85 | 86 | return S_OK; 87 | } 88 | 89 | HRESULT STDMETHODCALLTYPE OnDeviceAdded( LPCWSTR pwstrDeviceId ) { return S_OK; } 90 | HRESULT STDMETHODCALLTYPE OnDeviceRemoved( LPCWSTR pwstrDeviceId ) { return S_OK; } 91 | HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( LPCWSTR pwstrDeviceId, DWORD dwNewState ) { return S_OK; } 92 | HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( LPCWSTR pwstrDeviceId, const PROPERTYKEY key ) { return S_OK; } 93 | 94 | void do_register(sound_out_i_xaudio2 * p_instance) 95 | { 96 | if ( InterlockedIncrement( ®istered ) == 1 ) 97 | { 98 | pEnumerator = NULL; 99 | HRESULT hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IMMDeviceEnumerator ), ( void** ) &pEnumerator ); 100 | if ( SUCCEEDED( hr ) ) 101 | { 102 | pEnumerator->RegisterEndpointNotificationCallback( this ); 103 | registered = true; 104 | } 105 | } 106 | 107 | EnterCriticalSection( &lock ); 108 | instances.push_back( p_instance ); 109 | LeaveCriticalSection( &lock ); 110 | } 111 | 112 | void do_unregister( sound_out_i_xaudio2 * p_instance ) 113 | { 114 | if ( InterlockedDecrement( ®istered ) == 0 ) 115 | { 116 | if (pEnumerator) 117 | { 118 | pEnumerator->UnregisterEndpointNotificationCallback( this ); 119 | pEnumerator->Release(); 120 | pEnumerator = NULL; 121 | } 122 | registered = false; 123 | } 124 | 125 | EnterCriticalSection( &lock ); 126 | for ( std::vector::iterator it = instances.begin(); it < instances.end(); ++it ) 127 | { 128 | if ( *it == p_instance ) 129 | { 130 | instances.erase( it ); 131 | break; 132 | } 133 | } 134 | LeaveCriticalSection( &lock ); 135 | } 136 | } g_notifier; 137 | 138 | class sound_out_i_xaudio2 : public sound_out 139 | { 140 | class XAudio2_BufferNotify : public IXAudio2VoiceCallback 141 | { 142 | public: 143 | HANDLE hBufferEndEvent; 144 | 145 | XAudio2_BufferNotify() { 146 | hBufferEndEvent = NULL; 147 | hBufferEndEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); 148 | assert( hBufferEndEvent != NULL ); 149 | } 150 | 151 | ~XAudio2_BufferNotify() { 152 | CloseHandle( hBufferEndEvent ); 153 | hBufferEndEvent = NULL; 154 | } 155 | 156 | STDMETHOD_( void, OnBufferEnd ) ( void *pBufferContext ) { 157 | assert( hBufferEndEvent != NULL ); 158 | SetEvent( hBufferEndEvent ); 159 | sound_out_i_xaudio2 * psnd = ( sound_out_i_xaudio2 * ) pBufferContext; 160 | if ( psnd ) psnd->OnBufferEnd(); 161 | } 162 | 163 | 164 | // dummies: 165 | STDMETHOD_( void, OnVoiceProcessingPassStart ) ( UINT32 BytesRequired ) {} 166 | STDMETHOD_( void, OnVoiceProcessingPassEnd ) () {} 167 | STDMETHOD_( void, OnStreamEnd ) () {} 168 | STDMETHOD_( void, OnBufferStart ) ( void *pBufferContext ) {} 169 | STDMETHOD_( void, OnLoopEnd ) ( void *pBufferContext ) {} 170 | STDMETHOD_( void, OnVoiceError ) ( void *pBufferContext, HRESULT Error ) {}; 171 | }; 172 | 173 | void OnBufferEnd() 174 | { 175 | InterlockedDecrement( &buffered_count ); 176 | LONG buffer_read_cursor = this->buffer_read_cursor; 177 | samples_played += samples_in_buffer[ buffer_read_cursor ]; 178 | this->buffer_read_cursor = ( buffer_read_cursor + 1 ) % num_frames; 179 | } 180 | 181 | void * hwnd; 182 | bool paused; 183 | volatile bool device_changed; 184 | unsigned reopen_count; 185 | unsigned sample_rate, bytes_per_sample, max_samples_per_frame, num_frames; 186 | unsigned short nch; 187 | volatile LONG buffered_count; 188 | volatile LONG buffer_read_cursor; 189 | LONG buffer_write_cursor; 190 | 191 | volatile UINT64 samples_played; 192 | 193 | uint8_t * sample_buffer; 194 | UINT64 * samples_in_buffer; 195 | 196 | IXAudio2 *xaud; 197 | IXAudio2MasteringVoice *mVoice; // listener 198 | IXAudio2SourceVoice *sVoice; // sound source 199 | XAUDIO2_VOICE_STATE vState; 200 | XAudio2_BufferNotify notify; // buffer end notification 201 | public: 202 | sound_out_i_xaudio2() 203 | { 204 | paused = false; 205 | reopen_count = 0; 206 | buffered_count = 0; 207 | device_changed = false; 208 | 209 | xaud = NULL; 210 | mVoice = NULL; 211 | sVoice = NULL; 212 | sample_buffer = NULL; 213 | ZeroMemory( &vState, sizeof( vState ) ); 214 | 215 | g_notifier.do_register( this ); 216 | } 217 | 218 | virtual ~sound_out_i_xaudio2() 219 | { 220 | g_notifier.do_unregister( this ); 221 | 222 | close(); 223 | } 224 | 225 | void OnDeviceChanged() 226 | { 227 | device_changed = true; 228 | } 229 | 230 | virtual const char* open( void * hwnd, unsigned sample_rate, unsigned short nch, bool floating_point, unsigned max_samples_per_frame, unsigned num_frames ) 231 | { 232 | this->hwnd = hwnd; 233 | this->sample_rate = sample_rate; 234 | this->nch = nch; 235 | this->max_samples_per_frame = max_samples_per_frame; 236 | this->num_frames = num_frames; 237 | bytes_per_sample = floating_point ? 4 : 2; 238 | 239 | #ifdef HAVE_KS_HEADERS 240 | WAVEFORMATEXTENSIBLE wfx; 241 | wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 242 | wfx.Format.nChannels = nch; //1; 243 | wfx.Format.nSamplesPerSec = sample_rate; 244 | wfx.Format.nBlockAlign = bytes_per_sample * nch; //2; 245 | wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; 246 | wfx.Format.wBitsPerSample = floating_point ? 32 : 16; 247 | wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); 248 | wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample; 249 | wfx.SubFormat = floating_point ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM; 250 | wfx.dwChannelMask = nch == 2 ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_MONO; 251 | #else 252 | WAVEFORMATEX wfx; 253 | wfx.wFormatTag = floating_point ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; 254 | wfx.nChannels = nch; //1; 255 | wfx.nSamplesPerSec = sample_rate; 256 | wfx.nBlockAlign = bytes_per_sample * nch; //2; 257 | wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; 258 | wfx.wBitsPerSample = floating_point ? 32 : 16; 259 | wfx.cbSize = 0; 260 | #endif 261 | HRESULT hr = XAudio2Create( &xaud, 0 ); 262 | if (FAILED(hr)) return "Creating XAudio2 interface"; 263 | hr = xaud->CreateMasteringVoice( 264 | &mVoice, 265 | nch, 266 | sample_rate, 267 | 0, 268 | NULL, 269 | NULL ); 270 | if (FAILED(hr)) return "Creating XAudio2 mastering voice"; 271 | hr = xaud->CreateSourceVoice( &sVoice, &wfx, 0, 4.0f, ¬ify ); 272 | if (FAILED(hr)) return "Creating XAudio2 source voice"; 273 | hr = sVoice->Start( 0 ); 274 | if (FAILED(hr)) return "Starting XAudio2 voice"; 275 | hr = sVoice->SetFrequencyRatio((float)1.0f); 276 | if (FAILED(hr)) return "Setting XAudio2 voice frequency ratio"; 277 | device_changed = false; 278 | buffered_count = 0; 279 | buffer_read_cursor = 0; 280 | buffer_write_cursor = 0; 281 | samples_played = 0; 282 | sample_buffer = new uint8_t[ max_samples_per_frame * num_frames * bytes_per_sample ]; 283 | samples_in_buffer = new UINT64[ num_frames ]; 284 | memset( samples_in_buffer, 0, sizeof( UINT64 ) * num_frames ); 285 | return NULL; 286 | } 287 | 288 | void close() 289 | { 290 | if( sVoice ) { 291 | if( !paused ) { 292 | sVoice->Stop( 0 ); 293 | } 294 | sVoice->DestroyVoice(); 295 | sVoice = NULL; 296 | } 297 | 298 | if( mVoice ) { 299 | mVoice->DestroyVoice(); 300 | mVoice = NULL; 301 | } 302 | 303 | if( xaud ) { 304 | xaud->Release(); 305 | xaud = NULL; 306 | } 307 | 308 | delete [] sample_buffer; 309 | sample_buffer = NULL; 310 | delete [] samples_in_buffer; 311 | samples_in_buffer = NULL; 312 | } 313 | 314 | virtual const char* write_frame( void * buffer, unsigned num_samples, bool wait ) 315 | { 316 | if ( device_changed ) 317 | { 318 | close(); 319 | reopen_count = 5; 320 | device_changed = false; 321 | return 0; 322 | } 323 | 324 | if ( paused ) 325 | { 326 | if ( wait ) Sleep( MulDiv( num_samples / nch, 1000, sample_rate ) ); 327 | return 0; 328 | } 329 | 330 | if ( reopen_count ) 331 | { 332 | if ( ! --reopen_count ) 333 | { 334 | const char * err = open( hwnd, sample_rate, nch, bytes_per_sample == 4, max_samples_per_frame, num_frames ); 335 | if ( err ) 336 | { 337 | reopen_count = 60 * 5; 338 | return err; 339 | } 340 | } 341 | else 342 | { 343 | if ( wait ) Sleep( MulDiv( num_samples / nch, 1000, sample_rate ) ); 344 | return 0; 345 | } 346 | } 347 | 348 | for (;;) { 349 | sVoice->GetState( &vState ); 350 | assert( vState.BuffersQueued <= num_frames ); 351 | if( vState.BuffersQueued < num_frames ) { 352 | if( vState.BuffersQueued == 0 ) { 353 | // buffers ran dry 354 | } 355 | // there is at least one free buffer 356 | break; 357 | } else { 358 | // wait for one buffer to finish playing 359 | const DWORD timeout_ms = ( max_samples_per_frame / nch ) * num_frames * 1000 / sample_rate; 360 | if ( WaitForSingleObject( notify.hBufferEndEvent, timeout_ms ) == WAIT_TIMEOUT ) 361 | { 362 | // buffer has stalled, likely by the whole XAudio2 system failing, so we should tear it down and attempt to reopen it 363 | close(); 364 | reopen_count = 5; 365 | 366 | return 0; 367 | } 368 | } 369 | } 370 | samples_in_buffer[ buffer_write_cursor ] = num_samples / nch; 371 | XAUDIO2_BUFFER buf = {0}; 372 | unsigned num_bytes = num_samples * bytes_per_sample; 373 | buf.AudioBytes = num_bytes; 374 | buf.pAudioData = sample_buffer + max_samples_per_frame * buffer_write_cursor * bytes_per_sample; 375 | buf.pContext = this; 376 | buffer_write_cursor = ( buffer_write_cursor + 1 ) % num_frames; 377 | memcpy( ( void * ) buf.pAudioData, buffer, num_bytes ); 378 | if( sVoice->SubmitSourceBuffer( &buf ) == S_OK ) 379 | { 380 | InterlockedIncrement( &buffered_count ); 381 | return 0; 382 | } 383 | 384 | close(); 385 | reopen_count = 60 * 5; 386 | 387 | return 0; 388 | } 389 | 390 | virtual const char* pause( bool pausing ) 391 | { 392 | if ( pausing ) 393 | { 394 | if ( ! paused ) 395 | { 396 | paused = true; 397 | if ( !reopen_count ) 398 | { 399 | HRESULT hr = sVoice->Stop( 0 ); 400 | if ( FAILED(hr) ) 401 | { 402 | close(); 403 | reopen_count = 60 * 5; 404 | } 405 | } 406 | } 407 | } 408 | else 409 | { 410 | if ( paused ) 411 | { 412 | paused = false; 413 | if ( !reopen_count ) 414 | { 415 | HRESULT hr = sVoice->Start( 0 ); 416 | if ( FAILED(hr) ) 417 | { 418 | close(); 419 | reopen_count = 60 * 5; 420 | } 421 | } 422 | } 423 | } 424 | 425 | return 0; 426 | } 427 | 428 | virtual const char* set_ratio( double ratio ) 429 | { 430 | if ( !reopen_count && FAILED( sVoice->SetFrequencyRatio( static_cast(ratio) ) ) ) return "setting ratio"; 431 | return 0; 432 | } 433 | 434 | virtual double buffered() 435 | { 436 | if ( reopen_count ) return 0.0; 437 | sVoice->GetState( &vState ); 438 | double buffered_count = vState.BuffersQueued; 439 | INT64 samples_played = vState.SamplesPlayed - this->samples_played; 440 | buffered_count -= double( samples_played ) / double( max_samples_per_frame / nch ); 441 | return buffered_count; 442 | } 443 | }; 444 | 445 | void xaudio2_device_changed( sound_out_i_xaudio2 * p_instance ) 446 | { 447 | p_instance->OnDeviceChanged(); 448 | } 449 | 450 | sound_out * create_sound_out_xaudio2() 451 | { 452 | return new sound_out_i_xaudio2; 453 | } 454 | -------------------------------------------------------------------------------- /driver/vstmididrv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | VSTi MIDI Driver 3 | */ 4 | 5 | //#define DEBUG 6 | #define STRICT 7 | #ifndef _WIN32_WINNT 8 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 9 | #endif 10 | 11 | #if __DMC__ 12 | unsigned long _beginthreadex( void *security, unsigned stack_size, 13 | unsigned ( __stdcall *start_address )( void * ), void *arglist, 14 | unsigned initflag, unsigned *thrdaddr ); 15 | void _endthreadex( unsigned retval ); 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #if (_MSC_VER == 1700) 29 | #include 30 | #else 31 | #include "mmddk.h" 32 | extern "C" { 33 | BOOL WINAPI DriverCallback( DWORD dwCallBack, DWORD dwFlags, HDRVR hdrvr, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2 ); 34 | } 35 | #endif 36 | 37 | #include "sound_out.h" 38 | #include "VSTDriver.h" 39 | 40 | #define MAX_DRIVERS 2 41 | #define MAX_CLIENTS 1 // Per driver 42 | 43 | #define SAMPLES_PER_FRAME 88 * 2 44 | #define FRAMES_XAUDIO 15 45 | #define FRAMES_DSOUND 50 46 | #define SAMPLE_RATE_USED 44100 47 | 48 | struct Driver_Client { 49 | int allocated; 50 | DWORD instance; 51 | DWORD flags; 52 | DWORD_PTR callback; 53 | }; 54 | 55 | struct Driver { 56 | int open; 57 | int clientCount; 58 | HDRVR hdrvr; 59 | struct Driver_Client clients[MAX_CLIENTS]; 60 | } drivers[MAX_DRIVERS+1]; 61 | 62 | int driverCount; 63 | 64 | static volatile int OpenCount = 0; 65 | static volatile int modm_closed = 1; 66 | 67 | static CRITICAL_SECTION mim_section; 68 | static volatile int stop_thread = 0; 69 | static volatile int reset_synth = 0; 70 | static HANDLE hCalcThread = NULL; 71 | static DWORD processPriority; 72 | static HANDLE load_vstevent = NULL; 73 | 74 | static BOOL com_initialized = FALSE; 75 | static float sound_out_volume_float = 1.0; 76 | static sound_out * sound_driver = NULL; 77 | static VSTDriver * vst_driver = NULL; 78 | 79 | static void DoStartDriver(); 80 | static void DoStopDriver(); 81 | 82 | extern "C" HINSTANCE hinst_vst_driver = NULL; 83 | 84 | class message_window 85 | { 86 | HWND m_hWnd; 87 | ATOM class_atom; 88 | 89 | public: 90 | message_window() { 91 | static const TCHAR * class_name = _T("vstmididrv message window"); 92 | WNDCLASSEX cls = { 0 }; 93 | cls.cbSize = sizeof(cls); 94 | cls.lpfnWndProc = DefWindowProc; 95 | cls.hInstance = hinst_vst_driver; 96 | cls.lpszClassName = class_name; 97 | class_atom = RegisterClassEx( &cls ); 98 | if ( class_atom ) { 99 | m_hWnd = CreateWindowEx( 0, (LPCTSTR) class_atom, _T("vstmididrv"), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hinst_vst_driver, NULL ); 100 | } else { 101 | m_hWnd = NULL; 102 | } 103 | } 104 | 105 | ~message_window() 106 | { 107 | if ( IsWindow( m_hWnd ) ) DestroyWindow( m_hWnd ); 108 | if ( class_atom ) UnregisterClass( (LPCTSTR) class_atom, hinst_vst_driver ); 109 | } 110 | 111 | HWND get_hwnd() const { return m_hWnd; } 112 | }; 113 | 114 | message_window * g_msgwnd = NULL; 115 | 116 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ){ 117 | if (fdwReason == DLL_PROCESS_ATTACH){ 118 | DisableThreadLibraryCalls(hinstDLL); 119 | hinst_vst_driver = hinstDLL; 120 | g_msgwnd = new message_window; 121 | }else if(fdwReason == DLL_PROCESS_DETACH){ 122 | ; 123 | DoStopDriver(); 124 | delete g_msgwnd; 125 | } 126 | return TRUE; 127 | } 128 | 129 | STDAPI_(LONG) DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2){ 130 | 131 | switch(msg) { 132 | case DRV_FREE: // XXX never called 133 | return DRV_OK; 134 | case DRV_LOAD: 135 | memset(drivers, 0, sizeof(drivers)); 136 | driverCount = 0; 137 | return DRV_OK; 138 | case DRV_OPEN: 139 | { 140 | int driverNum; 141 | if (driverCount == MAX_DRIVERS) { 142 | return 0; 143 | } else { 144 | for (driverNum = 0; driverNum < MAX_DRIVERS; driverNum++) { 145 | if (!drivers[driverNum].open) { 146 | break; 147 | } 148 | if (driverNum == MAX_DRIVERS) { 149 | return 0; 150 | } 151 | } 152 | } 153 | drivers[driverNum].open = 1; 154 | drivers[driverNum].clientCount = 0; 155 | drivers[driverNum].hdrvr = hdrvr; 156 | driverCount++; 157 | } 158 | return DRV_OK; 159 | case DRV_CLOSE: // XXX never called 160 | { 161 | int i; 162 | for (i = 0; i < MAX_DRIVERS; i++) { 163 | if (drivers[i].open && drivers[i].hdrvr == hdrvr) { 164 | drivers[i].open = 0; 165 | --driverCount; 166 | return DRV_OK; 167 | } 168 | } 169 | } 170 | return DRV_CANCEL; 171 | case DRV_CONFIGURE: 172 | case DRV_DISABLE: 173 | case DRV_ENABLE: 174 | case DRV_EXITSESSION: 175 | case DRV_REMOVE: 176 | case DRV_INSTALL: 177 | case DRV_POWER: 178 | case DRV_QUERYCONFIGURE: 179 | return DRV_OK; 180 | } 181 | return DRV_OK; 182 | } 183 | 184 | HRESULT modGetCaps(UINT uDeviceID, PVOID capsPtr, DWORD capsSize) { 185 | MIDIOUTCAPSA * myCapsA; 186 | MIDIOUTCAPSW * myCapsW; 187 | MIDIOUTCAPS2A * myCaps2A; 188 | MIDIOUTCAPS2W * myCaps2W; 189 | 190 | CHAR synthName[] = "VST MIDI Synth"; 191 | WCHAR synthNameW[] = L"VST MIDI Synth"; 192 | 193 | CHAR synthPortA[] = " (port A)\0"; 194 | WCHAR synthPortAW[] = L" (port A)\0"; 195 | 196 | CHAR synthPortB[] = " (port B)\0"; 197 | WCHAR synthPortBW[] = L" (port B)\0"; 198 | 199 | switch (capsSize) { 200 | case (sizeof(MIDIOUTCAPSA)): 201 | myCapsA = (MIDIOUTCAPSA *)capsPtr; 202 | myCapsA->wMid = 0xffff; 203 | myCapsA->wPid = 0xffff; 204 | memcpy(myCapsA->szPname, synthName, strlen(synthName)); 205 | memcpy(myCapsA->szPname + strlen(synthName), uDeviceID ? synthPortB : synthPortA, sizeof(synthPortA)); 206 | myCapsA->wTechnology = MOD_MIDIPORT; 207 | myCapsA->vDriverVersion = 0x0090; 208 | myCapsA->wVoices = 0; 209 | myCapsA->wNotes = 0; 210 | myCapsA->wChannelMask = 0xffff; 211 | myCapsA->dwSupport = MIDICAPS_VOLUME; 212 | return MMSYSERR_NOERROR; 213 | 214 | case (sizeof(MIDIOUTCAPSW)): 215 | myCapsW = (MIDIOUTCAPSW *)capsPtr; 216 | myCapsW->wMid = 0xffff; 217 | myCapsW->wPid = 0xffff; 218 | memcpy(myCapsW->szPname, synthNameW, wcslen(synthNameW) * sizeof(wchar_t)); 219 | memcpy(myCapsW->szPname + wcslen(synthNameW), uDeviceID ? synthPortBW : synthPortAW, sizeof(synthPortAW)); 220 | myCapsW->wTechnology = MOD_MIDIPORT; 221 | myCapsW->vDriverVersion = 0x0090; 222 | myCapsW->wVoices = 0; 223 | myCapsW->wNotes = 0; 224 | myCapsW->wChannelMask = 0xffff; 225 | myCapsW->dwSupport = MIDICAPS_VOLUME; 226 | return MMSYSERR_NOERROR; 227 | 228 | case (sizeof(MIDIOUTCAPS2A)): 229 | myCaps2A = (MIDIOUTCAPS2A *)capsPtr; 230 | myCaps2A->wMid = 0xffff; 231 | myCaps2A->wPid = 0xffff; 232 | memcpy(myCaps2A->szPname, synthName, strlen(synthName)); 233 | memcpy(myCaps2A->szPname + strlen(synthName), uDeviceID ? synthPortB : synthPortA, sizeof(synthPortA)); 234 | myCaps2A->wTechnology = MOD_MIDIPORT; 235 | myCaps2A->vDriverVersion = 0x0090; 236 | myCaps2A->wVoices = 0; 237 | myCaps2A->wNotes = 0; 238 | myCaps2A->wChannelMask = 0xffff; 239 | myCaps2A->dwSupport = MIDICAPS_VOLUME; 240 | return MMSYSERR_NOERROR; 241 | 242 | case (sizeof(MIDIOUTCAPS2W)): 243 | myCaps2W = (MIDIOUTCAPS2W *)capsPtr; 244 | myCaps2W->wMid = 0xffff; 245 | myCaps2W->wPid = 0xffff; 246 | memcpy(myCaps2W->szPname, synthNameW, wcslen(synthNameW) * sizeof(wchar_t)); 247 | memcpy(myCaps2W->szPname + wcslen(synthNameW), uDeviceID ? synthPortBW : synthPortAW, sizeof(synthPortAW)); 248 | myCaps2W->wTechnology = MOD_MIDIPORT; 249 | myCaps2W->vDriverVersion = 0x0090; 250 | myCaps2W->wVoices = 0; 251 | myCaps2W->wNotes = 0; 252 | myCaps2W->wChannelMask = 0xffff; 253 | myCaps2W->dwSupport = MIDICAPS_VOLUME; 254 | return MMSYSERR_NOERROR; 255 | 256 | default: 257 | return MMSYSERR_ERROR; 258 | } 259 | } 260 | 261 | 262 | struct evbuf_t{ 263 | UINT uDeviceID; 264 | UINT uMsg; 265 | DWORD dwParam1; 266 | DWORD dwParam2; 267 | int exlen; 268 | unsigned char *sysexbuffer; 269 | }; 270 | #define EVBUFF_SIZE 512 271 | static struct evbuf_t evbuf[EVBUFF_SIZE]; 272 | static volatile LONG evbcount=0; 273 | static UINT evbwpoint=0; 274 | static UINT evbrpoint=0; 275 | static UINT evbsysexpoint; 276 | 277 | int vstsyn_buf_check(void){ 278 | int retval; 279 | retval = evbcount; 280 | return retval; 281 | } 282 | 283 | int vstsyn_play_some_data(void){ 284 | UINT uDeviceID; 285 | UINT uMsg; 286 | DWORD dwParam1; 287 | DWORD dwParam2; 288 | 289 | UINT evbpoint; 290 | MIDIHDR *IIMidiHdr; 291 | int exlen; 292 | unsigned char *sysexbuffer; 293 | int played; 294 | 295 | played=0; 296 | if( !vstsyn_buf_check() ){ 297 | played=~0; 298 | return played; 299 | } 300 | do{ 301 | EnterCriticalSection(&mim_section); 302 | evbpoint=evbrpoint; 303 | if (++evbrpoint >= EVBUFF_SIZE) 304 | evbrpoint -= EVBUFF_SIZE; 305 | 306 | uDeviceID=evbuf[evbpoint].uDeviceID; 307 | uMsg=evbuf[evbpoint].uMsg; 308 | dwParam1=evbuf[evbpoint].dwParam1; 309 | dwParam2=evbuf[evbpoint].dwParam2; 310 | exlen=evbuf[evbpoint].exlen; 311 | sysexbuffer=evbuf[evbpoint].sysexbuffer; 312 | 313 | LeaveCriticalSection(&mim_section); 314 | switch (uMsg) { 315 | case MODM_DATA: 316 | vst_driver->ProcessMIDIMessage(uDeviceID, dwParam1); 317 | break; 318 | case MODM_LONGDATA: 319 | #ifdef DEBUG 320 | FILE * logfile; 321 | logfile = fopen("c:\\dbglog2.log","at"); 322 | if(logfile!=NULL) { 323 | for(int i = 0 ; i < exlen ; i++) 324 | fprintf(logfile,"%x ", sysexbuffer[i]); 325 | fprintf(logfile,"\n"); 326 | } 327 | fclose(logfile); 328 | #endif 329 | vst_driver->ProcessSysEx(uDeviceID, sysexbuffer, exlen); 330 | free(sysexbuffer); 331 | break; 332 | } 333 | }while(InterlockedDecrement(&evbcount)); 334 | return played; 335 | } 336 | 337 | unsigned __stdcall threadfunc(LPVOID lpV){ 338 | unsigned i; 339 | int opend; 340 | BOOL floating_point; 341 | 342 | opend = 0; 343 | 344 | while(opend == 0 && stop_thread == 0) { 345 | Sleep(100); 346 | if (!com_initialized) { 347 | if (FAILED(CoInitialize(NULL))) continue; 348 | com_initialized = TRUE; 349 | } 350 | if (sound_driver == NULL) { 351 | sound_driver = create_sound_out_xaudio2(); 352 | const char * err = sound_driver->open(g_msgwnd->get_hwnd(), 44100, 2, floating_point = TRUE, SAMPLES_PER_FRAME, FRAMES_XAUDIO); 353 | if (err) { 354 | delete sound_driver; 355 | sound_driver = create_sound_out_ds(); 356 | err = sound_driver->open(g_msgwnd->get_hwnd(), 44100, 2, floating_point = FALSE, SAMPLES_PER_FRAME, FRAMES_DSOUND); 357 | } 358 | if (err) { 359 | delete sound_driver; 360 | sound_driver = NULL; 361 | continue; 362 | } 363 | } 364 | vst_driver = new VSTDriver; 365 | if (!vst_driver->OpenVSTDriver()) { 366 | delete vst_driver; 367 | vst_driver = NULL; 368 | continue; 369 | } 370 | if (load_vstevent) SetEvent(load_vstevent); 371 | opend = 1; 372 | } 373 | 374 | while(stop_thread == 0){ 375 | if (reset_synth != 0){ 376 | vst_driver->ResetDriver(); 377 | reset_synth = 0; 378 | } 379 | vstsyn_play_some_data(); 380 | if (floating_point) { 381 | float sound_buffer[SAMPLES_PER_FRAME]; 382 | vst_driver->RenderFloat( sound_buffer, SAMPLES_PER_FRAME / 2, sound_out_volume_float ); 383 | sound_driver->write_frame( sound_buffer, SAMPLES_PER_FRAME, true ); 384 | } else { 385 | short sound_buffer[SAMPLES_PER_FRAME]; 386 | vst_driver->Render( sound_buffer, SAMPLES_PER_FRAME / 2, sound_out_volume_float ); 387 | sound_driver->write_frame( sound_buffer, SAMPLES_PER_FRAME, true ); 388 | } 389 | } 390 | stop_thread=0; 391 | delete vst_driver; 392 | vst_driver = NULL; 393 | delete sound_driver; 394 | sound_driver = NULL; 395 | CoUninitialize(); 396 | _endthreadex(0); 397 | return 0; 398 | } 399 | 400 | void DoCallback(int driverNum, int clientNum, DWORD msg, DWORD param1, DWORD param2) { 401 | struct Driver_Client *client = &drivers[driverNum].clients[clientNum]; 402 | DriverCallback(client->callback, client->flags, drivers[driverNum].hdrvr, msg, client->instance, param1, param2); 403 | } 404 | 405 | void DoStartDriver() { 406 | if (modm_closed == 1) { 407 | DWORD result; 408 | unsigned int thrdaddr; 409 | InitializeCriticalSection(&mim_section); 410 | processPriority = GetPriorityClass(GetCurrentProcess()); 411 | SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); 412 | load_vstevent = CreateEvent( 413 | NULL, // default security attributes 414 | TRUE, // manual-reset event 415 | FALSE, // initial state is nonsignaled 416 | TEXT("VSTiEvent") // object name 417 | ); 418 | hCalcThread=(HANDLE)_beginthreadex(NULL,0,threadfunc,0,0,&thrdaddr); 419 | SetPriorityClass(hCalcThread, REALTIME_PRIORITY_CLASS); 420 | SetThreadPriority(hCalcThread, THREAD_PRIORITY_TIME_CRITICAL); 421 | result = WaitForSingleObject(load_vstevent,INFINITE); 422 | if (result == WAIT_OBJECT_0) 423 | { 424 | CloseHandle(load_vstevent); 425 | load_vstevent = NULL; 426 | } 427 | modm_closed = 0; 428 | } 429 | } 430 | 431 | void DoStopDriver() { 432 | if (modm_closed == 0){ 433 | stop_thread = 1; 434 | WaitForSingleObject(hCalcThread, INFINITE); 435 | CloseHandle(hCalcThread); 436 | // Somehow, the thread gets terminated before this is reached 437 | delete vst_driver; 438 | vst_driver = NULL; 439 | modm_closed = 1; 440 | SetPriorityClass(GetCurrentProcess(), processPriority); 441 | } 442 | DeleteCriticalSection(&mim_section); 443 | } 444 | 445 | void DoResetDriver(DWORD dwParam1, DWORD dwParam2) { 446 | reset_synth = 1; 447 | } 448 | 449 | LONG DoOpenDriver(struct Driver *driver, UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) { 450 | int clientNum; 451 | MIDIOPENDESC *desc; 452 | if (driver->clientCount == 0) { 453 | DoStartDriver(); 454 | DoResetDriver(dwParam1, dwParam2); 455 | clientNum = 0; 456 | } else if (driver->clientCount == MAX_CLIENTS) { 457 | return MMSYSERR_ALLOCATED; 458 | } else { 459 | int i; 460 | for (i = 0; i < MAX_CLIENTS; i++) { 461 | if (!driver->clients[i].allocated) { 462 | break; 463 | } 464 | } 465 | if (i == MAX_CLIENTS) { 466 | return MMSYSERR_ALLOCATED; 467 | } 468 | clientNum = i; 469 | } 470 | desc = (MIDIOPENDESC *)dwParam1; 471 | driver->clients[clientNum].allocated = 1; 472 | driver->clients[clientNum].flags = HIWORD(dwParam2); 473 | driver->clients[clientNum].callback = desc->dwCallback; 474 | driver->clients[clientNum].instance = desc->dwInstance; 475 | *(LONG *)dwUser = clientNum; 476 | driver->clientCount++; 477 | SetPriorityClass(GetCurrentProcess(), processPriority); 478 | DoCallback(uDeviceID, clientNum, MOM_OPEN, 0, 0); 479 | return MMSYSERR_NOERROR; 480 | } 481 | 482 | LONG DoCloseDriver(struct Driver *driver, UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) { 483 | if (!driver->clients[dwUser].allocated) { 484 | return MMSYSERR_INVALPARAM; 485 | } 486 | 487 | driver->clients[dwUser].allocated = 0; 488 | driver->clientCount--; 489 | if(driver->clientCount <= 0) { 490 | DoResetDriver(dwParam1, dwParam2); 491 | driver->clientCount = 0; 492 | } 493 | DoCallback(uDeviceID, dwUser, MOM_CLOSE, 0, 0); 494 | return MMSYSERR_NOERROR; 495 | } 496 | 497 | STDAPI_(LONG) midMessage(UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) { 498 | struct Driver *driver = &drivers[uDeviceID]; 499 | switch (uMsg) { 500 | case MIDM_OPEN: 501 | return DoOpenDriver(driver, uDeviceID, uMsg, dwUser, dwParam1, dwParam2); 502 | 503 | case MIDM_CLOSE: 504 | return DoCloseDriver(driver, uDeviceID, uMsg, dwUser, dwParam1, dwParam2); 505 | 506 | default: 507 | return MMSYSERR_NOERROR; 508 | break; 509 | } 510 | } 511 | 512 | STDAPI_(LONG) modMessage(UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ 513 | MIDIHDR *IIMidiHdr; 514 | UINT evbpoint, evw, evr; 515 | struct Driver *driver = &drivers[uDeviceID]; 516 | int exlen = 0; 517 | unsigned char *sysexbuffer = NULL ; 518 | DWORD result = 0; 519 | switch (uMsg) { 520 | case MODM_OPEN: 521 | return DoOpenDriver(driver, uDeviceID, uMsg, dwUser, dwParam1, dwParam2); 522 | break; 523 | case MODM_PREPARE: 524 | return MMSYSERR_NOTSUPPORTED; 525 | break; 526 | case MODM_UNPREPARE: 527 | return MMSYSERR_NOTSUPPORTED; 528 | break; 529 | case MODM_GETDEVCAPS: 530 | return modGetCaps(uDeviceID, (PVOID)dwParam1, dwParam2); 531 | break; 532 | case MODM_GETVOLUME : { 533 | *(LONG*)dwParam1 = static_cast(sound_out_volume_float * 0xFFFF); 534 | return MMSYSERR_NOERROR; 535 | } 536 | case MODM_SETVOLUME: { 537 | sound_out_volume_float = LOWORD(dwParam1) / (float)0xFFFF; 538 | return MMSYSERR_NOERROR; 539 | } 540 | case MODM_RESET: 541 | DoResetDriver(dwParam1, dwParam2); 542 | return MMSYSERR_NOERROR; 543 | case MODM_LONGDATA: 544 | IIMidiHdr = (MIDIHDR *)dwParam1; 545 | if( !(IIMidiHdr->dwFlags & MHDR_PREPARED) ) return MIDIERR_UNPREPARED; 546 | IIMidiHdr->dwFlags &= ~MHDR_DONE; 547 | IIMidiHdr->dwFlags |= MHDR_INQUEUE; 548 | IIMidiHdr = (MIDIHDR *) dwParam1; 549 | exlen=(int)IIMidiHdr->dwBufferLength; 550 | if( NULL == (sysexbuffer = (unsigned char *)malloc(exlen * sizeof(char)))){ 551 | return MMSYSERR_NOMEM; 552 | }else{ 553 | memcpy(sysexbuffer,IIMidiHdr->lpData,exlen); 554 | #ifdef DEBUG 555 | FILE * logfile; 556 | logfile = fopen("c:\\dbglog.log","at"); 557 | if(logfile!=NULL) { 558 | fprintf(logfile,"sysex %d byete\n", exlen); 559 | for(int i = 0 ; i < exlen ; i++) 560 | fprintf(logfile,"%x ", sysexbuffer[i]); 561 | fprintf(logfile,"\n"); 562 | } 563 | fclose(logfile); 564 | #endif 565 | } 566 | IIMidiHdr->dwFlags &= ~MHDR_INQUEUE; 567 | IIMidiHdr->dwFlags |= MHDR_DONE; 568 | DoCallback(uDeviceID, dwUser, MOM_DONE, dwParam1, 0); 569 | case MODM_DATA: 570 | EnterCriticalSection(&mim_section); 571 | evbpoint = evbwpoint; 572 | if (++evbwpoint >= EVBUFF_SIZE) 573 | evbwpoint -= EVBUFF_SIZE; 574 | evw = evbwpoint; 575 | evr = evbrpoint; 576 | evbuf[evbpoint].uDeviceID = !!uDeviceID; 577 | evbuf[evbpoint].uMsg = uMsg; 578 | evbuf[evbpoint].dwParam1 = dwParam1; 579 | evbuf[evbpoint].dwParam2 = dwParam2; 580 | evbuf[evbpoint].exlen=exlen; 581 | evbuf[evbpoint].sysexbuffer=sysexbuffer; 582 | LeaveCriticalSection(&mim_section); 583 | if (InterlockedIncrement(&evbcount) == EVBUFF_SIZE) { 584 | do 585 | { 586 | Sleep(1); 587 | } while (evbcount == EVBUFF_SIZE); 588 | } 589 | return MMSYSERR_NOERROR; 590 | break; 591 | case MODM_GETNUMDEVS: 592 | return 0x2; 593 | break; 594 | case MODM_CLOSE: 595 | return DoCloseDriver(driver, uDeviceID, uMsg, dwUser, dwParam1, dwParam2); 596 | break; 597 | default: 598 | return MMSYSERR_NOERROR; 599 | break; 600 | } 601 | } 602 | 603 | -------------------------------------------------------------------------------- /driver/vstmididrv.def: -------------------------------------------------------------------------------- 1 | LIBRARY "vstmididrv.dll" 2 | EXPORTS 3 | DriverProc PRIVATE 4 | modMessage PRIVATE 5 | midMessage PRIVATE 6 | -------------------------------------------------------------------------------- /driver/vstmididrv.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstmidi_win32drv", "vstmididrv.vcxproj", "{4666F6D4-704E-4223-B3A0-D27A4486C6A0}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Debug|Win32.Build.0 = Debug|Win32 16 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Debug|x64.ActiveCfg = Debug|x64 17 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Debug|x64.Build.0 = Debug|x64 18 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Release|Win32.ActiveCfg = Release|Win32 19 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Release|Win32.Build.0 = Release|Win32 20 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Release|x64.ActiveCfg = Release|x64 21 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /driver/vstmididrv.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | vstmidi_win32drv 41 | {4666F6D4-704E-4223-B3A0-D27A4486C6A0} 42 | vstmidi_win32drv 43 | AtlProj 44 | 45 | 46 | 47 | DynamicLibrary 48 | Static 49 | Static 50 | Unicode 51 | true 52 | 53 | 54 | DynamicLibrary 55 | Static 56 | Static 57 | Unicode 58 | true 59 | 60 | 61 | DynamicLibrary 62 | false 63 | Static 64 | Unicode 65 | 66 | 67 | DynamicLibrary 68 | false 69 | Static 70 | Unicode 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | <_ProjectFileVersion>10.0.40219.1 94 | $(ProjectDir)\..\output\ 95 | $(ProjectDir)\..\output\64\ 96 | true 97 | true 98 | $(ProjectDir)\..\output\ 99 | $(ProjectDir)\..\output\64\ 100 | false 101 | false 102 | AllRules.ruleset 103 | AllRules.ruleset 104 | 105 | 106 | 107 | 108 | AllRules.ruleset 109 | AllRules.ruleset 110 | 111 | 112 | 113 | 114 | $(IncludePath) 115 | $(IncludePath) 116 | $(DXSDK_DIR)lib\x86;$(LibraryPath);$(ProjectDir)\..\external_packages\lib 117 | $(DXSDK_DIR)lib\x86;$(LibraryPath);$(ProjectDir)\..\external_packages\lib 118 | $(DXSDK_DIR)lib\x86;$(LibraryPath);$(ProjectDir)\..\external_packages\lib 119 | $(DXSDK_DIR)lib\x86;$(LibraryPath);$(ProjectDir)\..\external_packages\lib 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | vstmidi_win32drv.tlb 132 | 133 | 134 | Disabled 135 | $(ProjectDir)\..\external_packages;%(AdditionalIncludeDirectories) 136 | _DEBUG;_USRDLL;I_ASM;%(PreprocessorDefinitions) 137 | EnableFastChecks 138 | MultiThreadedDebugDLL 139 | true 140 | true 141 | 142 | 143 | stdafx.h 144 | Level3 145 | true 146 | EditAndContinue 147 | Default 148 | 149 | 150 | _DEBUG;%(PreprocessorDefinitions) 151 | 0x0409 152 | 153 | 154 | /MACHINE:I386 %(AdditionalOptions) 155 | dxguid.lib;winmm.lib;Shlwapi.lib;%(AdditionalDependencies) 156 | LinkVerboseLib 157 | $(OutDir)\vstmididrv.dll 158 | true 159 | false 160 | %(IgnoreSpecificDefaultLibraries) 161 | .\vstmididrv.def 162 | true 163 | vstmididrv.pdb 164 | Windows 165 | false 166 | 167 | 168 | .vstmidi_win32drv.lib 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | vstmidi_win32drv.tlb 184 | 185 | 186 | Disabled 187 | $(ProjectDir)\..\external_packages;%(AdditionalIncludeDirectories) 188 | _DEBUG;_USRDLL;I_ASM;%(PreprocessorDefinitions) 189 | EnableFastChecks 190 | MultiThreadedDebugDLL 191 | true 192 | true 193 | 194 | 195 | stdafx.h 196 | Level3 197 | true 198 | ProgramDatabase 199 | Default 200 | 201 | 202 | _DEBUG;%(PreprocessorDefinitions) 203 | 0x0409 204 | 205 | 206 | dxguid.lib;winmm.lib;Shlwapi.lib;%(AdditionalDependencies) 207 | LinkVerboseLib 208 | $(OutDir)\vstmididrv.dll 209 | true 210 | false 211 | %(IgnoreSpecificDefaultLibraries) 212 | .\vstmididrv.def 213 | true 214 | vstmididrv.pdb 215 | Windows 216 | false 217 | 218 | 219 | .vstmidi_win32drv.lib 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | vstmidi_win32drv.tlb 235 | 236 | 237 | MinSpace 238 | Default 239 | false 240 | Speed 241 | true 242 | $(ProjectDir)\..\external_packages;%(AdditionalIncludeDirectories) 243 | NDEBUG;_USRDLL;I_ASM;%(PreprocessorDefinitions) 244 | true 245 | MultiThreaded 246 | true 247 | 248 | 249 | stdafx.h 250 | Level3 251 | true 252 | Default 253 | Fast 254 | 255 | 256 | NDEBUG;%(PreprocessorDefinitions) 257 | 0x0409 258 | 259 | 260 | /MACHINE:I386 %(AdditionalOptions) 261 | dxguid.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Shlwapi.lib;%(AdditionalDependencies) 262 | LinkVerboseLib 263 | $(OutDir)\vstmididrv.dll 264 | true 265 | false 266 | .\vstmididrv.def 267 | vstmididrv.pdb 268 | Windows 269 | false 270 | 271 | 272 | vstmidi_win32drv.lib 273 | true 274 | true 275 | true 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | vstmidi_win32drv.tlb 291 | 292 | 293 | MinSpace 294 | Default 295 | false 296 | Speed 297 | true 298 | $(ProjectDir)\..\external_packages;%(AdditionalIncludeDirectories) 299 | NDEBUG;_USRDLL;I_ASM;%(PreprocessorDefinitions) 300 | true 301 | MultiThreaded 302 | true 303 | 304 | 305 | stdafx.h 306 | Level3 307 | true 308 | Default 309 | Fast 310 | 311 | 312 | NDEBUG;%(PreprocessorDefinitions) 313 | 0x0409 314 | 315 | 316 | dxguid.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Shlwapi.lib;%(AdditionalDependencies) 317 | LinkVerboseLib 318 | $(OutDir)\vstmididrv.dll 319 | true 320 | false 321 | .\vstmididrv.def 322 | vstmididrv.pdb 323 | Windows 324 | false 325 | 326 | 327 | vstmidi_win32drv.lib 328 | true 329 | true 330 | true 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /drivercfg/DlgTabCtrl.h: -------------------------------------------------------------------------------- 1 | #if !defined(AFX_PAGECTRL_H__20020427_0B15_DD2C_8E81_0080AD509054__INCLUDED_) 2 | #define AFX_PAGECTRL_H__20020427_0B15_DD2C_8E81_0080AD509054__INCLUDED_ 3 | 4 | #pragma once 5 | 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // Tab controls with embedded views 8 | // 9 | // Written by Bjarke Viksoe (bjarke@viksoe.dk) 10 | // Copyright (c) 2002 Bjarke Viksoe. 11 | // 12 | // Add the following macro to the parent's message map: 13 | // REFLECT_NOTIFICATIONS() 14 | // 15 | // This code may be used in compiled form in any way you desire. This 16 | // source file may be redistributed by any means PROVIDING it is 17 | // not sold for profit without the authors written consent, and 18 | // providing that this notice and the authors name is included. 19 | // 20 | // This file is provided "as is" with no expressed or implied warranty. 21 | // The author accepts no liability if it causes any damage to you or your 22 | // computer whatsoever. It's free, so don't hassle me about it. 23 | // 24 | // Beware of bugs. 25 | // 26 | 27 | #ifndef __cplusplus 28 | #error WTL requires C++ compilation (use a .cpp suffix) 29 | #endif 30 | 31 | #ifndef __ATLAPP_H__ 32 | #error DlgTabCtrlCtrl.h requires atlapp.h to be included first 33 | #endif 34 | 35 | 36 | 37 | ///////////////////////////////////////////////////////////////////////////// 38 | // CDlgContainerCtrl - A container for Dialog views 39 | 40 | #ifndef TCN_INITIALIZE 41 | #define TCN_INITIALIZE TCN_FIRST-10 42 | #define TCN_INSERTITEM TCN_FIRST-11 43 | #define TCN_DELETEITEM TCN_FIRST-12 44 | #endif // TCN_INITIALIZE 45 | 46 | #ifndef ETDT_ENABLETAB 47 | #define ETDT_ENABLETAB 6 48 | #endif 49 | 50 | template< class T, class TBase = CWindow, class TWinTraits = CControlWinTraits > 51 | class ATL_NO_VTABLE CDlgContainerImpl : 52 | public CWindowImpl< T, TBase, TWinTraits > 53 | { 54 | public: 55 | CSimpleValArray m_aViews; 56 | HWND m_hWndClient; 57 | int m_iCurPos; 58 | 59 | CDlgContainerImpl() : 60 | m_iCurPos(-1), 61 | m_hWndClient(NULL) 62 | { 63 | } 64 | 65 | // Operations 66 | 67 | BOOL SubclassWindow(HWND hWnd) 68 | { 69 | ATLASSERT(m_hWnd == NULL); 70 | ATLASSERT(::IsWindow(hWnd)); 71 | BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); 72 | if( bRet ) _Init(); 73 | return bRet; 74 | } 75 | 76 | BOOL PreTranslateMessage(MSG* pMsg) 77 | { 78 | if( m_hWndClient ) { 79 | TCHAR szClassName[8] = { 0 }; 80 | ::GetClassName(m_hWndClient, szClassName, 7); 81 | if( ::lstrcmp(_T("#32770"), szClassName) == 0 ) return ::IsDialogMessage(m_hWndClient, pMsg); 82 | } 83 | return FALSE; 84 | } 85 | 86 | int AddItem(HWND hWnd) 87 | { 88 | ATLASSERT(::IsWindow(hWnd)); 89 | // Add view 90 | m_aViews.Add(hWnd); 91 | // Initially we hide the view 92 | CWindow wnd = hWnd; 93 | wnd.ShowWindow(SW_HIDE); 94 | // FIX: Important; see Q149501 95 | wnd.ModifyStyleEx(0, WS_EX_CONTROLPARENT); 96 | // Notify owner 97 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_INSERTITEM }; 98 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 99 | // Return new position 100 | return m_aViews.GetSize() - 1; 101 | } 102 | BOOL RemoveItem(HWND hWnd) 103 | { 104 | ATLASSERT(::IsWindow(hWnd)); 105 | int iPos = m_aViews.Find(hWnd); 106 | return RemoveItem(iPos); 107 | } 108 | BOOL RemoveItem(int iPos) 109 | { 110 | if( iPos < 0 || iPos >= m_aViews.GetSize() ) return NULL; 111 | // Notify owner 112 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_DELETEITEM }; 113 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 114 | // Remove view 115 | return m_aViews.RemoveAt(iPos); 116 | } 117 | HWND GetItem(int iPos) const 118 | { 119 | if( iPos < 0 || iPos >= m_aViews.GetSize() ) return NULL; 120 | return m_aViews[iPos]; 121 | } 122 | int GetItemCount() const 123 | { 124 | return m_aViews.GetSize(); 125 | } 126 | BOOL SetCurSel(int iPos) 127 | { 128 | if( iPos < 0 || iPos >= m_aViews.GetSize() ) return FALSE; 129 | if( iPos == m_iCurPos ) return TRUE; // Already selected 130 | // Ask user if it's OK to change selection... 131 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_SELCHANGING }; 132 | LRESULT lRes = ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 133 | if( lRes!=0 ) return FALSE; // User declined 134 | // Assign new state 135 | HWND hWndActive = GetItem(m_iCurPos); 136 | HWND hWndNew = GetItem(iPos); 137 | m_iCurPos = iPos; 138 | m_hWndClient = hWndNew; 139 | // Hide old view 140 | if( hWndActive ) ::SetWindowPos(hWndActive, NULL, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW); 141 | // Resize new view into place 142 | BOOL bDummy; 143 | OnSize(0, 0, 0, bDummy); 144 | if( hWndNew ) ::SetWindowPos(hWndNew, NULL, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); 145 | // If this is the first selection, make sure container gets focus. 146 | // Otherwise give focus to new view (Windows might hang in case an old 147 | // view still has focus and IsDialogMessage() is called!) 148 | if( hWndActive == NULL ) { 149 | SetFocus(); 150 | } 151 | else if( IsChild(::GetFocus()) ) { 152 | //::SetFocus(hWndNew); 153 | //::PostMessage(hWndNew, WM_NEXTDLGCTL, 0, (LPARAM) FALSE); 154 | ::SetFocus(::GetWindow(hWndNew, GW_CHILD)); 155 | } 156 | // Send notification 157 | nmh.code = TCN_SELCHANGE; 158 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 159 | return TRUE; 160 | } 161 | int GetCurSel() const 162 | { 163 | return m_iCurPos; 164 | } 165 | 166 | // Message map and handlers 167 | 168 | BEGIN_MSG_MAP(CDlgContainerImpl) 169 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 170 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 171 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 172 | MESSAGE_HANDLER(WM_SIZE, OnSize) 173 | CHAIN_CLIENT_COMMANDS() 174 | REFLECT_NOTIFICATIONS() 175 | END_MSG_MAP() 176 | 177 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 178 | { 179 | _Init(); 180 | return 0; 181 | } 182 | LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 183 | { 184 | return TRUE; // View fills entire client area 185 | } 186 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 187 | { 188 | // Set focus to first child of the view instead 189 | if( m_hWndClient == NULL ) return 0; 190 | //HWND hWndChild = ::GetWindow(hWndNew, GW_CHILD); 191 | HWND hWndChild = ::GetNextDlgTabItem(m_hWndClient, NULL, FALSE); 192 | if( hWndChild ) ::SetFocus(hWndChild); 193 | return 0; 194 | } 195 | LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 196 | { 197 | if( m_hWndClient == NULL ) return 0; 198 | RECT rc; 199 | GetClientRect(&rc); 200 | ::SetWindowPos(m_hWndClient, NULL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_NOACTIVATE | SWP_NOZORDER); 201 | return 0; 202 | } 203 | 204 | // Implementation 205 | 206 | void _Init() 207 | { 208 | // FIX: Important; see Q149501 209 | ModifyStyleEx(0, WS_EX_CONTROLPARENT); 210 | // This is a little WTL subclass helper notification 211 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_INITIALIZE }; 212 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 213 | } 214 | }; 215 | 216 | class CDlgContainerCtrl : public CDlgContainerImpl 217 | { 218 | public: 219 | DECLARE_WND_CLASS(_T("WTL_DlgContainer")) 220 | }; 221 | 222 | 223 | 224 | ///////////////////////////////////////////////////////////////////////////// 225 | // CDialogTabCtrl - A Tab like control with active pages/dialogs 226 | 227 | template< class T, class TBase = CTabCtrl, class TWinTraits = CControlWinTraits > 228 | class ATL_NO_VTABLE CDialogTabImpl : 229 | public CWindowImpl< T, TBase, TWinTraits > 230 | { 231 | public: 232 | DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) 233 | 234 | CDlgContainerCtrl m_ctrlViews; 235 | HWND m_hWndClient; 236 | 237 | // Operations 238 | 239 | BOOL SubclassWindow(HWND hWnd) 240 | { 241 | ATLASSERT(m_hWnd == NULL); 242 | ATLASSERT(::IsWindow(hWnd)); 243 | BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); 244 | if( bRet ) _Init(); 245 | return bRet; 246 | } 247 | 248 | BOOL InsertItem(int nItem, LPTCITEM pItem, HWND hWnd) 249 | { 250 | ATLASSERT(nItem==GetItemCount()); // Only append at this time! 251 | // Notify owner 252 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_INSERTITEM }; 253 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 254 | // Set the window parent (for correct resizing) 255 | ::SetParent(hWnd, m_hWndClient); 256 | // Add view and tab 257 | m_ctrlViews.AddItem(hWnd); 258 | BOOL bRes = (int) TBase::InsertItem(nItem, pItem) != -1; 259 | // Resize client 260 | BOOL bDummy; 261 | OnSize(WM_SIZE, 0, 0, bDummy); 262 | return bRes; 263 | } 264 | BOOL DeleteItem(int nItem) 265 | { 266 | // Notify owner 267 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_DELETEITEM }; 268 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 269 | // Remove view and tab 270 | m_ctrlViews.RemoveItem(nItem); 271 | return TBase::DeleteItem(nItem); 272 | } 273 | BOOL DeleteAllItems() 274 | { 275 | while( m_ctrlViews.GetItemCount() > 0 ) m_ctrlViews.RemoveItem(0); 276 | return TBase::DeleteAllItems(); 277 | } 278 | int SetCurSel(int iTab) 279 | { 280 | // Trigger first tab selection 281 | int iLastTab = TBase::SetCurSel(iTab); 282 | if( iLastTab != -1 ) { 283 | // Tab controls will not send notifications on TCM_SETCURSEL. 284 | // I hate that! So I'll send it instead... 285 | NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_SELCHANGE }; 286 | ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh); 287 | } 288 | return iLastTab; 289 | } 290 | HWND GetContainer() const 291 | { 292 | return m_hWndClient; 293 | } 294 | 295 | // Enable Windows XP controls for dialogs/tabs 296 | HRESULT Uxtheme_EnableThemeDialogTexture(HWND hWnd, DWORD dwFlags) 297 | { 298 | HINSTANCE hDll; 299 | HRESULT Hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED); 300 | if( (hDll = ::LoadLibrary(_T("uxtheme.dll"))) != NULL ) { 301 | typedef HRESULT (WINAPI * ENABLETHEMEDIALOGTEXTURE)(HWND, DWORD); 302 | ENABLETHEMEDIALOGTEXTURE pfnETDT; 303 | if( (pfnETDT = (ENABLETHEMEDIALOGTEXTURE) ::GetProcAddress(hDll, "EnableThemeDialogTexture")) != NULL ) { 304 | Hr = pfnETDT(hWnd, dwFlags); 305 | } 306 | ::FreeLibrary(hDll); 307 | } 308 | return Hr; 309 | } 310 | 311 | // Message map and handlers 312 | 313 | BEGIN_MSG_MAP(CDialogTabImpl) 314 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 315 | MESSAGE_HANDLER(WM_SIZE, OnSize) 316 | MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 317 | REFLECTED_NOTIFY_CODE_HANDLER(TCN_SELCHANGE, OnTabSelect) 318 | CHAIN_CLIENT_COMMANDS() 319 | END_MSG_MAP() 320 | 321 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 322 | { 323 | LRESULT lRes = DefWindowProc(); 324 | _Init(); 325 | return lRes; 326 | } 327 | LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 328 | { 329 | if( m_hWndClient == NULL ) return 0; 330 | RECT rc; 331 | GetClientRect(&rc); 332 | AdjustRect(FALSE, &rc); 333 | ::SetWindowPos(m_hWndClient, NULL, 334 | rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 335 | SWP_NOACTIVATE | SWP_NOZORDER); 336 | return 0; 337 | } 338 | LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) 339 | { 340 | // Need to repaint only the outer regions of the tab control. 341 | // The tab's client area is filled by views, so there is no need 342 | // to paint that area. Also an embedded ListView control sometimes fail 343 | // to repaint properly if we don't do this... 344 | CDCHandle dc((HDC)wParam); 345 | RECT rc; 346 | GetClientRect(&rc); 347 | CRgn rgn1, rgn2, rgn; 348 | rgn1.CreateRectRgnIndirect(&rc); 349 | AdjustRect(FALSE, &rc); 350 | rgn2.CreateRectRgnIndirect(&rc); 351 | rgn.CreateRectRgnIndirect(&rc); 352 | rgn.CombineRgn(rgn1, rgn2, RGN_DIFF); 353 | dc.FillRgn(rgn, ::GetSysColorBrush(COLOR_BTNFACE)); 354 | return TRUE; 355 | } 356 | 357 | LRESULT OnTabSelect(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled) 358 | { 359 | int iIndex = GetCurSel(); 360 | m_ctrlViews.SetCurSel(iIndex); 361 | bHandled = FALSE; 362 | return 0; 363 | } 364 | 365 | // Implementation 366 | 367 | void _Init() 368 | { 369 | // Create dialog container 370 | m_hWndClient = m_ctrlViews.Create(m_hWnd, rcDefault); 371 | ATLASSERT(::IsWindow(m_hWndClient)); 372 | // FIX: Important; see Q149501 373 | ModifyStyleEx(0, WS_EX_CONTROLPARENT); 374 | } 375 | }; 376 | 377 | class CDialogTabCtrl : public CDialogTabImpl 378 | { 379 | public: 380 | DECLARE_WND_SUPERCLASS(_T("WTL_DialogTabCtrl"), GetWndClassName()) 381 | }; 382 | 383 | 384 | #endif // !defined(AFX_PAGECTRL_H__20020427_0B15_DD2C_8E81_0080AD509054__INCLUDED_) 385 | -------------------------------------------------------------------------------- /drivercfg/MainDlg.h: -------------------------------------------------------------------------------- 1 | // MainDlg.h : interface of the CMainDlg class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "resource.h" 9 | #include "DlgTabCtrl.h" 10 | #include "Views.h" 11 | 12 | 13 | #pragma once 14 | 15 | class CMainDlg : public CDialogImpl, public CUpdateUI, 16 | public CMessageFilter, public CIdleHandler 17 | { 18 | public: 19 | enum { IDD = IDD_MAINDLG }; 20 | CDialogTabCtrl m_ctrlTab; 21 | CView1 m_view1; 22 | CView2 m_view2; 23 | 24 | virtual BOOL PreTranslateMessage(MSG* pMsg) 25 | { 26 | return CWindow::IsDialogMessage(pMsg); 27 | } 28 | 29 | virtual BOOL OnIdle() 30 | { 31 | return FALSE; 32 | } 33 | 34 | BEGIN_UPDATE_UI_MAP(CMainDlg) 35 | END_UPDATE_UI_MAP() 36 | 37 | BEGIN_MSG_MAP(CMainDlg) 38 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 39 | MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 40 | COMMAND_ID_HANDLER(IDOK, OnOK) 41 | COMMAND_ID_HANDLER(IDCANCEL, OnCancel) 42 | REFLECT_NOTIFICATIONS(); 43 | END_MSG_MAP() 44 | 45 | // Handler prototypes (uncomment arguments if needed): 46 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 47 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 48 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 49 | 50 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 51 | { 52 | // center the dialog on the screen 53 | CenterWindow(); 54 | // set icons 55 | HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON)); 56 | SetIcon(hIcon, TRUE); 57 | HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON)); 58 | SetIcon(hIconSmall, FALSE); 59 | m_ctrlTab.SubclassWindow(GetDlgItem(IDC_TAB)); 60 | m_view1.Create(m_hWnd); 61 | m_view2.Create(m_hWnd); 62 | TCITEM tci = { 0 }; 63 | tci.mask = TCIF_TEXT; 64 | tci.pszText = _T("VST settings"); 65 | m_ctrlTab.InsertItem(0, &tci, m_view1); 66 | tci.pszText = _T("Advanced"); 67 | m_ctrlTab.InsertItem(1, &tci, m_view2); 68 | m_ctrlTab.SetCurSel(0); 69 | 70 | // register object for message filtering and idle updates 71 | CMessageLoop* pLoop = _Module.GetMessageLoop(); 72 | ATLASSERT(pLoop != NULL); 73 | pLoop->AddMessageFilter(this); 74 | pLoop->AddIdleHandler(this); 75 | 76 | UIAddChildWindowContainer(m_hWnd); 77 | 78 | return TRUE; 79 | } 80 | 81 | LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 82 | { 83 | // unregister message filtering and idle updates 84 | CMessageLoop* pLoop = _Module.GetMessageLoop(); 85 | ATLASSERT(pLoop != NULL); 86 | pLoop->RemoveMessageFilter(this); 87 | pLoop->RemoveIdleHandler(this); 88 | 89 | return 0; 90 | } 91 | 92 | LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 93 | { 94 | // TODO: Add validation code 95 | CloseDialog(wID); 96 | return 0; 97 | } 98 | 99 | LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 100 | { 101 | CloseDialog(wID); 102 | return 0; 103 | } 104 | 105 | void CloseDialog(int nVal) 106 | { 107 | DestroyWindow(); 108 | ::PostQuitMessage(nVal); 109 | } 110 | }; 111 | -------------------------------------------------------------------------------- /drivercfg/Views.h: -------------------------------------------------------------------------------- 1 | #if !defined(AFX_VIEWS_H__20020629_8D64_963C_A351_0080AD509054__INCLUDED_) 2 | #define AFX_VIEWS_H__20020629_8D64_963C_A351_0080AD509054__INCLUDED_ 3 | 4 | #include 5 | #include 6 | #include "utf8conv.h" 7 | #include 8 | using namespace std; 9 | using namespace utf8util; 10 | #include "../driver/VSTDriver.h" 11 | typedef AEffect* (*PluginEntryProc) (audioMasterCallback audioMaster); 12 | static INT_PTR CALLBACK EditorProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 13 | 14 | // for VSTDriver 15 | extern "C" HINSTANCE hinst_vst_driver = NULL; 16 | 17 | struct MyDLGTEMPLATE: DLGTEMPLATE 18 | { 19 | WORD ext[3]; 20 | MyDLGTEMPLATE () 21 | { memset (this, 0, sizeof(*this)); }; 22 | }; 23 | 24 | std::wstring stripExtension(const std::wstring& fileName) 25 | { 26 | const int length = fileName.length(); 27 | for (int i=0; i!=length; ++i) 28 | { 29 | if (fileName[i]=='.') 30 | { 31 | return fileName.substr(0,i); 32 | } 33 | } 34 | return fileName; 35 | } 36 | 37 | void settings_load(VSTDriver * effect) 38 | { 39 | ifstream file; 40 | long lResult; 41 | TCHAR vst_path[256] = {0}; 42 | ULONG size; 43 | CRegKeyEx reg; 44 | wstring fname; 45 | lResult = reg.Create(HKEY_CURRENT_USER, L"Software\\VSTi Driver", 0, 0, KEY_READ | KEY_WOW64_32KEY); 46 | if (lResult == ERROR_SUCCESS){ 47 | lResult = reg.QueryStringValue(L"plugin",NULL,&size); 48 | if (lResult == ERROR_SUCCESS) { 49 | reg.QueryStringValue(L"plugin",vst_path,&size); 50 | wstring ext = vst_path; 51 | fname = stripExtension(ext); 52 | fname += L".set"; 53 | file.open(fname,ifstream::binary); 54 | if (file.good()) 55 | { 56 | file.seekg(0,ifstream::end); 57 | unsigned int chunk_size = file.tellg(); 58 | file.seekg(0); 59 | vector chunk; 60 | chunk.resize( chunk_size ); 61 | file.read( (char*) chunk.data(), chunk_size ); 62 | if (effect) effect->setChunk( chunk.data(), chunk_size ); 63 | } 64 | file.close(); 65 | } 66 | reg.Close(); 67 | } 68 | } 69 | 70 | void settings_save(VSTDriver * effect) 71 | { 72 | ofstream file; 73 | long lResult; 74 | TCHAR vst_path[256] = {0}; 75 | ULONG size; 76 | CRegKeyEx reg; 77 | wstring fname; 78 | lResult = reg.Create(HKEY_CURRENT_USER, L"Software\\VSTi Driver", 0, 0, KEY_WRITE | KEY_WOW64_32KEY); 79 | if (lResult == ERROR_SUCCESS){ 80 | lResult = reg.QueryStringValue(L"plugin",NULL,&size); 81 | if (lResult == ERROR_SUCCESS) { 82 | reg.QueryStringValue(L"plugin",vst_path,&size); 83 | wstring ext = vst_path; 84 | fname = stripExtension(ext); 85 | fname += L".set"; 86 | file.open(fname,ofstream::binary); 87 | if (file.good()) 88 | { 89 | vector chunk; 90 | if (effect) effect->getChunk( chunk ); 91 | file.write( ( const char * ) chunk.data(), chunk.size() ); 92 | } 93 | file.close(); 94 | } 95 | reg.Close(); 96 | } 97 | } 98 | 99 | using namespace std; 100 | using namespace utf8util; 101 | #if _MSC_VER > 1000 102 | #pragma once 103 | #endif // _MSC_VER > 1000 104 | 105 | class CView1 : public CDialogImpl 106 | { 107 | CEdit vst_info; 108 | CButton vst_load, vst_configure; 109 | CStatic vst_vendor, vst_effect, vst_product; 110 | TCHAR vst_path[MAX_PATH]; 111 | VSTDriver * effect; 112 | public: 113 | enum { IDD = IDD_MAIN }; 114 | BEGIN_MSG_MAP(CView1) 115 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialogView1) 116 | COMMAND_ID_HANDLER(IDC_VSTLOAD,OnButtonAdd) 117 | COMMAND_ID_HANDLER(IDC_VSTCONFIG,OnButtonConfig) 118 | END_MSG_MAP() 119 | 120 | CView1() { effect = NULL; } 121 | ~CView1() { free_vst(); } 122 | 123 | void load_settings() 124 | { 125 | long lResult; 126 | vst_path[0] = 0; 127 | ULONG size; 128 | CRegKeyEx reg; 129 | lResult = reg.Create(HKEY_CURRENT_USER, L"Software\\VSTi Driver"); 130 | if (lResult == ERROR_SUCCESS){ 131 | lResult = reg.QueryStringValue(L"plugin",NULL,&size); 132 | if (lResult == ERROR_SUCCESS) { 133 | reg.QueryStringValue(L"plugin",vst_path,&size); 134 | } 135 | reg.Close(); 136 | vst_info.SetWindowText(vst_path); 137 | load_vst(vst_path); 138 | if(effect) vst_configure.EnableWindow(effect->hasEditor()); 139 | } 140 | 141 | } 142 | 143 | LRESULT OnButtonAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/ ) 144 | { 145 | TCHAR szFileName[MAX_PATH]; 146 | LPCTSTR sFiles = 147 | L"VSTi instruments (*.dll)\0*.dll\0" 148 | L"All Files (*.*)\0*.*\0\0"; 149 | CFileDialog dlg( TRUE, NULL, vst_path, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, sFiles); 150 | if (dlg.DoModal() == IDOK) 151 | { 152 | lstrcpy(szFileName,dlg.m_szFileName); 153 | if (load_vst(szFileName)) 154 | { 155 | HKEY hKey, hSubKey; 156 | long lResult; 157 | CRegKeyEx reg; 158 | lResult = reg.Create(HKEY_CURRENT_USER, L"Software\\VSTi Driver", 0, 0, KEY_WRITE | KEY_WOW64_32KEY); 159 | reg.SetStringValue(L"plugin",szFileName); 160 | reg.Close(); 161 | vst_info.SetWindowText(szFileName); 162 | vst_configure.EnableWindow(effect->hasEditor()); 163 | } 164 | // do stuff 165 | } 166 | return 0; 167 | } 168 | 169 | LRESULT OnButtonConfig(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/ ) 170 | { 171 | if(effect && effect->hasEditor()) 172 | { 173 | HWND m_hWnd = GetAncestor(this->m_hWnd, GA_ROOT); 174 | ::EnableWindow(m_hWnd, FALSE); 175 | effect->displayEditorModal(); 176 | ::EnableWindow(m_hWnd, TRUE); 177 | } 178 | return 0; 179 | } 180 | 181 | void free_vst() 182 | { 183 | settings_save( effect ); 184 | delete effect; 185 | effect = NULL; 186 | } 187 | 188 | BOOL load_vst(TCHAR * szPluginPath) 189 | { 190 | free_vst(); 191 | effect = new VSTDriver; 192 | if (!effect->OpenVSTDriver(szPluginPath)) 193 | { 194 | delete effect; 195 | effect = NULL; 196 | MessageBox(L"This is NOT a VSTi synth!"); 197 | vst_effect.SetWindowText(L"No VSTi loaded"); 198 | vst_vendor.SetWindowText(L"No VSTi loaded"); 199 | vst_product.SetWindowText(L"No VSTi loaded"); 200 | vst_info.SetWindowText(L"No VSTi loaded"); 201 | return FALSE; 202 | } 203 | 204 | string conv; 205 | effect->getEffectName(conv); 206 | wstring effect_str = utf16_from_ansi(conv); 207 | vst_effect.SetWindowText(effect_str.c_str()); 208 | effect->getVendorString(conv); 209 | wstring vendor_str = utf16_from_ansi(conv); 210 | vst_vendor.SetWindowText(vendor_str.c_str()); 211 | effect->getProductString(conv); 212 | wstring product_str = utf16_from_ansi(conv); 213 | vst_product.SetWindowText(product_str.c_str()); 214 | 215 | settings_load( effect ); 216 | 217 | return TRUE; 218 | } 219 | 220 | LRESULT OnInitDialogView1(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 221 | { 222 | effect = NULL; 223 | vst_load= GetDlgItem(IDC_VSTLOAD); 224 | vst_info = GetDlgItem(IDC_VSTLOADED); 225 | vst_configure = GetDlgItem(IDC_VSTCONFIG); 226 | vst_effect = GetDlgItem(IDC_EFFECT); 227 | vst_vendor = GetDlgItem(IDC_VENDOR); 228 | vst_product = GetDlgItem(IDC_PRODUCT); 229 | vst_effect.SetWindowText(L"No VSTi loaded"); 230 | vst_vendor.SetWindowText(L"No VSTi loaded"); 231 | vst_product.SetWindowText(L"No VSTi loaded"); 232 | vst_info.SetWindowText(L"No VSTi loaded"); 233 | load_settings(); 234 | return TRUE; 235 | } 236 | }; 237 | 238 | 239 | BOOL IsWin8OrNewer() 240 | { 241 | OSVERSIONINFOEX osvi; 242 | BOOL bOsVersionInfoEx; 243 | ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); 244 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 245 | bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi); 246 | if( bOsVersionInfoEx == FALSE ) return FALSE; 247 | if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && 248 | ( osvi.dwMajorVersion > 6 || 249 | ( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 1 ) ) ) 250 | return TRUE; 251 | return FALSE; 252 | } 253 | 254 | class CView2 : public CDialogImpl 255 | { 256 | CComboBox synthlist; 257 | CButton apply; 258 | BOOL win8; 259 | 260 | struct SDriverInfo 261 | { 262 | CString driver_path; 263 | CSimpleArray driver_names; 264 | }; 265 | 266 | CSimpleArray drivers; 267 | 268 | typedef DWORD (STDAPICALLTYPE * pmodMessage)(UINT uDeviceID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2); 269 | 270 | 271 | public: 272 | enum { IDD = IDD_ADVANCED }; 273 | BEGIN_MSG_MAP(CView1) 274 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialogView2) 275 | COMMAND_ID_HANDLER(IDC_SNAPPLY,OnButtonApply) 276 | END_MSG_MAP() 277 | 278 | LRESULT OnInitDialogView2(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 279 | { 280 | synthlist = GetDlgItem(IDC_SYNTHLIST); 281 | apply = GetDlgItem(IDC_SNAPPLY); 282 | win8 = IsWin8OrNewer(); 283 | win8 ? load_midisynths_manual() : load_midisynths_mapper(); 284 | return TRUE; 285 | } 286 | 287 | LRESULT OnButtonApply( WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/ ) 288 | { 289 | win8 ? set_midisynth_manual() : set_midisynth_mapper(); 290 | return 0; 291 | 292 | } 293 | 294 | 295 | void set_midisynth() 296 | { 297 | CRegKeyEx reg; 298 | CRegKeyEx subkey; 299 | CString device_name; 300 | long lRet; 301 | int selection = synthlist.GetCurSel(); 302 | int n = synthlist.GetLBTextLen(selection); 303 | synthlist.GetLBText(selection,device_name.GetBuffer(n)); 304 | lRet = reg.Create(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia"); 305 | lRet = reg.DeleteSubKey(L"MIDIMap"); 306 | lRet = subkey.Create(reg,L"MIDIMap"); 307 | lRet = subkey.SetStringValue(L"szPname",device_name); 308 | if (lRet == ERROR_SUCCESS) 309 | { 310 | MessageBox(L"MIDI synth set!",L"Notice.",MB_ICONINFORMATION); 311 | } 312 | else 313 | { 314 | MessageBox(L"Can't set MIDI registry key",L"Damn!",MB_ICONSTOP); 315 | } 316 | device_name.ReleaseBuffer(n); 317 | subkey.Close(); 318 | reg.Close(); 319 | } 320 | 321 | /* These only work on Windows 6.1 and older */ 322 | void set_midisynth_mapper() 323 | { 324 | CRegKeyEx reg; 325 | CRegKeyEx subkey; 326 | CString device_name; 327 | long lRet; 328 | int selection = synthlist.GetCurSel(); 329 | int n = synthlist.GetLBTextLen(selection); 330 | synthlist.GetLBText(selection,device_name.GetBuffer(n)); 331 | device_name.ReleaseBuffer(n); 332 | lRet = reg.Create(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_WOW64_32KEY); 333 | lRet = reg.DeleteSubKey(L"MIDIMap"); 334 | lRet = subkey.Create(reg, L"MIDIMap", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); 335 | lRet = subkey.SetStringValue(L"szPname",device_name); 336 | if (lRet == ERROR_SUCCESS) 337 | { 338 | MessageBox(L"MIDI synth set!",L"Notice.",MB_ICONINFORMATION); 339 | } 340 | else 341 | { 342 | MessageBox(L"Can't set MIDI registry key",L"Damn!",MB_ICONSTOP); 343 | } 344 | subkey.Close(); 345 | reg.Close(); 346 | } 347 | 348 | void load_midisynths_mapper() 349 | { 350 | LONG lResult; 351 | CRegKeyEx reg; 352 | CString device_name; 353 | ULONG size = 128; 354 | lResult = reg.Create(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WOW64_32KEY); 355 | reg.QueryStringValue(L"szPname",device_name.GetBuffer(size),&size); 356 | reg.Close(); 357 | device_name.ReleaseBuffer(size); 358 | int device_count = midiOutGetNumDevs(); 359 | for (int i = 0; i < device_count; ++i) { 360 | MIDIOUTCAPS Caps; 361 | ZeroMemory(&Caps, sizeof(Caps)); 362 | MMRESULT Error = midiOutGetDevCaps(i, &Caps, sizeof(Caps)); 363 | if (Error != MMSYSERR_NOERROR) 364 | continue; 365 | synthlist.AddString(Caps.szPname); 366 | } 367 | int index = 0; 368 | index = synthlist.FindStringExact(-1,device_name); 369 | if (index == CB_ERR) index = 0; 370 | synthlist.SetCurSel(index); 371 | } 372 | 373 | /* In Windows 6.2 and newer, the MIDI mapper module ignores the 374 | * mapping sub-keys, so we have to enumerate the drivers and their 375 | * names manually, then replace the primary driver path with the 376 | * sole default the user requests. */ 377 | void set_midisynth_manual() 378 | { 379 | LONG lResult; 380 | CRegKeyEx reg; 381 | DWORD index = 0; 382 | DWORD subindex; 383 | DWORD device_number = 1; 384 | DWORD name_length; 385 | DWORD type; 386 | CString device_name; 387 | CString value_name; 388 | CString value_number; 389 | CSimpleArray old_value_names; 390 | 391 | int selection = synthlist.GetCurSel(); 392 | int n = synthlist.GetLBTextLen( selection ); 393 | synthlist.GetLBText( selection, device_name.GetBuffer( n ) ); 394 | device_name.ReleaseBuffer( n ); 395 | 396 | lResult = reg.Create( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE | KEY_WOW64_32KEY ); 397 | if ( lResult == ERROR_SUCCESS ) 398 | { 399 | do 400 | { 401 | name_length = 64; 402 | lResult = RegEnumValue( reg, index++, value_name.GetBuffer( 64 ), &name_length, NULL, &type, NULL, NULL ); 403 | if ( lResult == ERROR_MORE_DATA ) continue; 404 | if ( lResult != ERROR_SUCCESS ) break; 405 | if ( type != REG_SZ ) continue; 406 | 407 | value_name.ReleaseBuffer( name_length ); 408 | 409 | if ( !_tcscmp( value_name, _T("midi") ) || 410 | ( !_tcsncmp( value_name, _T("midi"), 4 ) && 411 | _tcscmp( value_name, _T("midimapper") ) ) ) 412 | { 413 | old_value_names.Add( value_name ); 414 | } 415 | } 416 | while ( lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA ); 417 | 418 | for ( index = 0; index < old_value_names.GetSize(); index++ ) 419 | { 420 | reg.DeleteValue( old_value_names[ index ] ); 421 | } 422 | 423 | for ( index = 0; index < drivers.GetSize(); index++ ) 424 | { 425 | for ( subindex = 0; subindex < drivers[ index ].driver_names.GetSize(); subindex++ ) 426 | { 427 | if ( !_tcscmp( drivers[ index ].driver_names[ subindex ], device_name ) ) 428 | { 429 | reg.SetStringValue( _T("midi"), drivers[ index ].driver_path ); 430 | break; 431 | } 432 | } 433 | if ( subindex == drivers[ index ].driver_names.GetSize() ) 434 | { 435 | _itot_s( device_number++, value_number.GetBuffer( 16 ), 16, 10 ); 436 | value_number.ReleaseBuffer(); 437 | value_name = "midi"; 438 | value_name += value_number; 439 | reg.SetStringValue( value_name, drivers[ index ].driver_path ); 440 | } 441 | } 442 | } 443 | } 444 | 445 | void load_midisynths_manual() 446 | { 447 | HRESULT hResult; 448 | LONG lResult; 449 | CRegKeyEx reg; 450 | CString value_name; 451 | CString device_path; 452 | CString system_path; 453 | CString device_full_path; 454 | CString device_name; 455 | HDRVR hDriver; 456 | HMODULE hModule; 457 | pmodMessage themodMessage; 458 | ULONG size; 459 | BOOL default_found = FALSE; 460 | DWORD default_index = 0; 461 | DWORD index = 0; 462 | DWORD type; 463 | DWORD name_length; 464 | DWORD path_length; 465 | DWORD driver_count; 466 | DWORD driver_number; 467 | MIDIOUTCAPS driver_caps; 468 | 469 | lResult = reg.Create( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE | KEY_WOW64_32KEY ); 470 | if ( lResult == ERROR_SUCCESS ) 471 | { 472 | do 473 | { 474 | SDriverInfo driver; 475 | name_length = 64; 476 | path_length = MAX_PATH; 477 | lResult = RegEnumValue( reg, index++, value_name.GetBuffer( 64 ), &name_length, NULL, &type, (LPBYTE) device_path.GetBuffer( MAX_PATH ), &path_length ); 478 | if ( lResult == ERROR_MORE_DATA ) continue; 479 | if ( lResult != ERROR_SUCCESS ) break; 480 | if ( type != REG_SZ ) continue; 481 | 482 | value_name.ReleaseBuffer( name_length ); 483 | device_path.ReleaseBuffer( path_length ); 484 | 485 | if ( !_tcscmp( value_name, _T("midi") ) || 486 | ( !_tcsncmp( value_name, _T("midi"), 4 ) && 487 | _tcscmp( value_name, _T("midimapper") ) ) ) 488 | { 489 | hDriver = OpenDriver( value_name, NULL, NULL ); 490 | 491 | if ( hDriver ) 492 | { 493 | hModule = GetDriverModuleHandle( hDriver ); 494 | if ( hModule ) 495 | { 496 | themodMessage = (pmodMessage) GetProcAddress( hModule, "modMessage" ); 497 | if ( themodMessage ) 498 | { 499 | driver_count = themodMessage( 0, MODM_GETNUMDEVS, NULL, NULL, NULL ); 500 | 501 | for ( driver_number = 0; driver_number < driver_count; driver_number++ ) 502 | { 503 | hResult = themodMessage( driver_number, MODM_GETDEVCAPS, NULL, reinterpret_cast( &driver_caps ), sizeof(driver_caps) ); 504 | if ( hResult == MMSYSERR_NOERROR ) 505 | { 506 | driver.driver_names.Add( CString( driver_caps.szPname ) ); 507 | synthlist.AddString( driver_caps.szPname ); 508 | } 509 | } 510 | 511 | if ( driver.driver_names.GetSize() ) 512 | { 513 | if ( !_tcscmp( value_name, _T("midi") ) ) 514 | { 515 | default_found = TRUE; 516 | } 517 | else if ( !default_found ) 518 | { 519 | default_index += driver.driver_names.GetSize(); 520 | } 521 | 522 | driver.driver_path = device_path; 523 | 524 | drivers.Add( driver ); 525 | } 526 | } 527 | } 528 | 529 | CloseDriver( hDriver, NULL, NULL ); 530 | } 531 | else 532 | { 533 | driver.driver_path = device_path; 534 | driver.driver_names.Add( device_path ); 535 | 536 | drivers.Add( driver ); 537 | } 538 | } 539 | } 540 | while ( lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA ); 541 | } 542 | synthlist.SetCurSel( default_index ); 543 | } 544 | }; 545 | 546 | 547 | 548 | #endif // !defined(AFX_VIEWS_H__20020629_8D64_963C_A351_0080AD509054__INCLUDED_) 549 | 550 | -------------------------------------------------------------------------------- /drivercfg/drivercfg.cpp: -------------------------------------------------------------------------------- 1 | // drivercfg.cpp : main source file for drivercfg.exe 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "resource.h" 6 | 7 | #include "MainDlg.h" 8 | 9 | CAppModule _Module; 10 | 11 | int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT) 12 | { 13 | CMessageLoop theLoop; 14 | _Module.AddMessageLoop(&theLoop); 15 | 16 | CMainDlg dlgMain; 17 | 18 | if(dlgMain.Create(NULL) == NULL) 19 | { 20 | ATLTRACE(_T("Main dialog creation failed!\n")); 21 | return 0; 22 | } 23 | 24 | dlgMain.ShowWindow(nCmdShow); 25 | 26 | int nRet = theLoop.Run(); 27 | 28 | _Module.RemoveMessageLoop(); 29 | return nRet; 30 | } 31 | 32 | int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) 33 | { 34 | HRESULT hRes = ::CoInitialize(NULL); 35 | // If you are running on NT 4.0 or higher you can use the following call instead to 36 | // make the EXE free threaded. This means that calls come in on a random RPC thread. 37 | // HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); 38 | ATLASSERT(SUCCEEDED(hRes)); 39 | 40 | // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used 41 | ::DefWindowProc(NULL, 0, 0, 0L); 42 | 43 | AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls 44 | 45 | hRes = _Module.Init(NULL, hInstance); 46 | ATLASSERT(SUCCEEDED(hRes)); 47 | 48 | int nRet = Run(lpstrCmdLine, nCmdShow); 49 | 50 | _Module.Term(); 51 | ::CoUninitialize(); 52 | 53 | return nRet; 54 | } 55 | -------------------------------------------------------------------------------- /drivercfg/drivercfg.h: -------------------------------------------------------------------------------- 1 | // drivercfg.h 2 | -------------------------------------------------------------------------------- /drivercfg/drivercfg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/drivercfg/drivercfg.ico -------------------------------------------------------------------------------- /drivercfg/drivercfg.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/drivercfg/drivercfg.rc -------------------------------------------------------------------------------- /drivercfg/drivercfg.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "drivercfg", "drivercfg.vcxproj", "{AF13E822-617D-4B1E-A092-C9C9B07C1E05}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {AF13E822-617D-4B1E-A092-C9C9B07C1E05}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {AF13E822-617D-4B1E-A092-C9C9B07C1E05}.Debug|Win32.Build.0 = Debug|Win32 14 | {AF13E822-617D-4B1E-A092-C9C9B07C1E05}.Release|Win32.ActiveCfg = Release|Win32 15 | {AF13E822-617D-4B1E-A092-C9C9B07C1E05}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /drivercfg/drivercfg.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {AF13E822-617D-4B1E-A092-C9C9B07C1E05} 23 | 24 | 25 | 26 | Application 27 | true 28 | Unicode 29 | 30 | 31 | Application 32 | false 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | Unicode 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Debug 55 | Debug 56 | true 57 | C:\codere\wtl\include;$(IncludePath) 58 | 59 | 60 | Release 61 | Release 62 | false 63 | $(LibraryPath) 64 | C:\codere\wtl\include;$(IncludePath) 65 | 66 | 67 | Release 68 | Release 69 | false 70 | $(LibraryPath) 71 | C:\codere\wtl\include;$(IncludePath) 72 | 73 | 74 | 75 | Use 76 | Level3 77 | MultiThreadedDebug 78 | true 79 | EditAndContinue 80 | EnableFastChecks 81 | Disabled 82 | WIN32;_WINDOWS;STRICT;_DEBUG;%(PreprocessorDefinitions) 83 | 84 | 85 | Windows 86 | MachineX86 87 | true 88 | winmm.lib;%(AdditionalDependencies) 89 | ../output/vstmididrvcfg.exe 90 | 91 | 92 | 0x0409 93 | $(IntDir);%(AdditionalIncludeDirectories) 94 | _DEBUG;%(PreprocessorDefinitions) 95 | 96 | 97 | false 98 | Win32 99 | _DEBUG;%(PreprocessorDefinitions) 100 | drivercfg.h 101 | drivercfg_i.c 102 | drivercfg_p.c 103 | true 104 | $(IntDir)/drivercfg.tlb 105 | 106 | 107 | 108 | 109 | 110 | 111 | NotUsing 112 | Level3 113 | MultiThreaded 114 | 115 | 116 | 117 | 118 | WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) 119 | 120 | 121 | Windows 122 | MachineX86 123 | winmm.lib;%(AdditionalDependencies) 124 | false 125 | ../output/vstmididrvcfg.exe 126 | 127 | 128 | 0x0409 129 | $(IntDir);%(AdditionalIncludeDirectories) 130 | NDEBUG;%(PreprocessorDefinitions) 131 | 132 | 133 | false 134 | Win32 135 | NDEBUG;%(PreprocessorDefinitions) 136 | drivercfg.h 137 | drivercfg_i.c 138 | drivercfg_p.c 139 | true 140 | $(IntDir)/drivercfg.tlb 141 | 142 | 143 | 144 | 145 | 146 | 147 | Use 148 | Level3 149 | MultiThreaded 150 | 151 | 152 | 153 | 154 | WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) 155 | 156 | 157 | Windows 158 | winmm.lib;%(AdditionalDependencies) 159 | false 160 | ../output/64/vstmididrvcfg.exe 161 | 162 | 163 | 0x0409 164 | $(IntDir);%(AdditionalIncludeDirectories) 165 | NDEBUG;%(PreprocessorDefinitions) 166 | 167 | 168 | false 169 | NDEBUG;%(PreprocessorDefinitions) 170 | drivercfg.h 171 | drivercfg_i.c 172 | drivercfg_p.c 173 | true 174 | $(IntDir)/drivercfg.tlb 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | Create 184 | Create 185 | Create 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /drivercfg/drivercfg.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /drivercfg/res/drivercfg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/drivercfg/res/drivercfg.ico -------------------------------------------------------------------------------- /drivercfg/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/drivercfg/resource.h -------------------------------------------------------------------------------- /drivercfg/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/drivercfg/small.ico -------------------------------------------------------------------------------- /drivercfg/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // drivercfg.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | #if (_ATL_VER < 0x0700) 8 | #include 9 | #endif //(_ATL_VER < 0x0700) 10 | -------------------------------------------------------------------------------- /drivercfg/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | // Change these values to use different versions 9 | #define WINVER 0x0500 10 | #define _WIN32_WINNT 0x0501 11 | #define _WIN32_IE 0x0501 12 | #define _RICHEDIT_VER 0x0200 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | extern CAppModule _Module; 23 | 24 | #include 25 | 26 | #if defined _M_IX86 27 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 28 | #elif defined _M_IA64 29 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 30 | #elif defined _M_X64 31 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 32 | #else 33 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 34 | #endif 35 | -------------------------------------------------------------------------------- /drivercfg/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /drivercfg/utf8conv.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // FILE: utf8conv.h 4 | // 5 | // Header file defining helper functions for converting strings 6 | // between Unicode UTF-8 and UTF-16. 7 | // 8 | // UTF-8 is stored in std::string; UTF-16 is stored in std::wstring. 9 | // 10 | // This code just uses Win32 Platform SDK and C++ standard library; 11 | // so it can be used also with the Express editions of Visual Studio. 12 | // 13 | // 14 | // February 4th, 2011 15 | // 16 | // by Giovanni Dicanio 17 | // 18 | ////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | #pragma once 22 | 23 | 24 | //------------------------------------------------------------------------ 25 | // INCLUDES 26 | //------------------------------------------------------------------------ 27 | 28 | #include // variable argument lists... 29 | #include // ...and vsprintf_s 30 | 31 | #include // std::exception 32 | #include // STL string classes 33 | 34 | #include // Win32 Platform SDK main header 35 | 36 | 37 | 38 | namespace utf8util { 39 | 40 | 41 | //------------------------------------------------------------------------ 42 | // Exception class representing an error occurred during UTF-8 conversion. 43 | //------------------------------------------------------------------------ 44 | class utf8_error 45 | : public std::exception 46 | { 47 | public: 48 | 49 | // Constructs an utf8_error with a message string that can use a 50 | // printf-like syntax for formatting. 51 | explicit utf8_error(const char * format, ...); 52 | 53 | // Override from std::exception::what() 54 | const char * what() const; 55 | 56 | 57 | // 58 | // IMPLEMENTATION 59 | // 60 | private: 61 | char m_message[512]; // buffer for error message 62 | }; 63 | 64 | 65 | inline utf8_error::utf8_error(const char * format, ...) 66 | { 67 | // Format error message in buffer 68 | va_list args; 69 | va_start(args, format); 70 | vsprintf_s(m_message, format, args); 71 | va_end(args); 72 | } 73 | 74 | 75 | inline const char * utf8_error::what() const 76 | { 77 | return m_message; 78 | } 79 | 80 | //------------------------------------------------------------------------ 81 | 82 | inline std::wstring utf16_from_ansi(const std::string & utf8) 83 | { 84 | // 85 | // Special case of empty input string 86 | // 87 | if (utf8.empty()) 88 | return std::wstring(); 89 | // 90 | // Get length (in wchar_t's) of resulting UTF-16 string 91 | // 92 | const int utf16_length = ::MultiByteToWideChar( 93 | CP_ACP, // convert from ANSI 94 | 0, // default flags 95 | utf8.data(), // source UTF-8 string 96 | utf8.length(), // length (in chars) of source UTF-8 string 97 | NULL, // unused - no conversion done in this step 98 | 0 // request size of destination buffer, in wchar_t's 99 | ); 100 | if (utf16_length == 0) 101 | { 102 | // Error 103 | DWORD error = ::GetLastError(); 104 | throw utf8_error( 105 | "Can't get length of UTF-16 string (MultiByteToWideChar set last error to %lu).", 106 | error); 107 | } 108 | // 109 | // Allocate destination buffer for UTF-16 string 110 | // 111 | std::wstring utf16; 112 | utf16.resize(utf16_length); 113 | 114 | 115 | // 116 | // Do the conversion from UTF-8 to UTF-16 117 | // 118 | if ( ! ::MultiByteToWideChar( 119 | CP_UTF8, // convert from UTF-8 120 | 0, // default flags 121 | utf8.data(), // source UTF-8 string 122 | utf8.length(), // length (in chars) of source UTF-8 string 123 | &utf16[0], // destination buffer 124 | utf16.length() // size of destination buffer, in wchar_t's 125 | ) ) 126 | { 127 | // Error 128 | DWORD error = ::GetLastError(); 129 | throw utf8_error( 130 | "Can't convert string from UTF-8 to UTF-16 (MultiByteToWideChar set last error to %lu).", 131 | error); 132 | } 133 | // 134 | // Return resulting UTF-16 string 135 | // 136 | return utf16; 137 | } 138 | 139 | 140 | 141 | //------------------------------------------------------------------------ 142 | // Converts a string from UTF-8 to UTF-16. 143 | // On error, can throw an utf8_error exception. 144 | //------------------------------------------------------------------------ 145 | inline std::wstring utf16_from_utf8(const std::string & utf8) 146 | { 147 | // 148 | // Special case of empty input string 149 | // 150 | if (utf8.empty()) 151 | return std::wstring(); 152 | 153 | 154 | // 155 | // Get length (in wchar_t's) of resulting UTF-16 string 156 | // 157 | const int utf16_length = ::MultiByteToWideChar( 158 | CP_UTF8, // convert from UTF-8 159 | 0, // default flags 160 | utf8.data(), // source UTF-8 string 161 | utf8.length(), // length (in chars) of source UTF-8 string 162 | NULL, // unused - no conversion done in this step 163 | 0 // request size of destination buffer, in wchar_t's 164 | ); 165 | if (utf16_length == 0) 166 | { 167 | // Error 168 | DWORD error = ::GetLastError(); 169 | throw utf8_error( 170 | "Can't get length of UTF-16 string (MultiByteToWideChar set last error to %lu).", 171 | error); 172 | } 173 | 174 | 175 | // 176 | // Allocate destination buffer for UTF-16 string 177 | // 178 | std::wstring utf16; 179 | utf16.resize(utf16_length); 180 | 181 | 182 | // 183 | // Do the conversion from UTF-8 to UTF-16 184 | // 185 | if ( ! ::MultiByteToWideChar( 186 | CP_UTF8, // convert from UTF-8 187 | 0, // default flags 188 | utf8.data(), // source UTF-8 string 189 | utf8.length(), // length (in chars) of source UTF-8 string 190 | &utf16[0], // destination buffer 191 | utf16.length() // size of destination buffer, in wchar_t's 192 | ) ) 193 | { 194 | // Error 195 | DWORD error = ::GetLastError(); 196 | throw utf8_error( 197 | "Can't convert string from UTF-8 to UTF-16 (MultiByteToWideChar set last error to %lu).", 198 | error); 199 | } 200 | 201 | // 202 | // Return resulting UTF-16 string 203 | // 204 | return utf16; 205 | } 206 | 207 | 208 | //------------------------------------------------------------------------ 209 | // Converts a string from UTF-16 to UTF-8. 210 | // On error, can throw an utf8_error exception. 211 | //------------------------------------------------------------------------ 212 | inline std::string utf8_from_utf16(const std::wstring & utf16) 213 | { 214 | // 215 | // Special case of empty input string 216 | // 217 | if (utf16.empty()) 218 | return std::string(); 219 | 220 | 221 | // 222 | // Get length (in chars) of resulting UTF-8 string 223 | // 224 | const int utf8_length = ::WideCharToMultiByte( 225 | CP_UTF8, // convert to UTF-8 226 | 0, // default flags 227 | utf16.data(), // source UTF-16 string 228 | utf16.length(), // source string length, in wchar_t's, 229 | NULL, // unused - no conversion required in this step 230 | 0, // request buffer size 231 | NULL, NULL // unused 232 | ); 233 | if (utf8_length == 0) 234 | { 235 | // Error 236 | DWORD error = ::GetLastError(); 237 | throw utf8_error( 238 | "Can't get length of UTF-8 string (WideCharToMultiByte set last error to %lu).", 239 | error); 240 | } 241 | 242 | 243 | // 244 | // Allocate destination buffer for UTF-8 string 245 | // 246 | std::string utf8; 247 | utf8.resize(utf8_length); 248 | 249 | 250 | // 251 | // Do the conversion from UTF-16 to UTF-8 252 | // 253 | if ( ! ::WideCharToMultiByte( 254 | CP_UTF8, // convert to UTF-8 255 | 0, // default flags 256 | utf16.data(), // source UTF-16 string 257 | utf16.length(), // source string length, in wchar_t's, 258 | &utf8[0], // destination buffer 259 | utf8.length(), // destination buffer size, in chars 260 | NULL, NULL // unused 261 | ) ) 262 | { 263 | // Error 264 | DWORD error = ::GetLastError(); 265 | throw utf8_error( 266 | "Can't convert string from UTF-16 to UTF-8 (WideCharToMultiByte set last error to %lu).", 267 | error); 268 | } 269 | 270 | 271 | // 272 | // Return resulting UTF-8 string 273 | // 274 | return utf8; 275 | } 276 | 277 | 278 | } // namespace utf8util 279 | 280 | 281 | ////////////////////////////////////////////////////////////////////////// 282 | 283 | -------------------------------------------------------------------------------- /external_packages/aeffect.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/external_packages/aeffect.h -------------------------------------------------------------------------------- /external_packages/aeffectx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/external_packages/aeffectx.h -------------------------------------------------------------------------------- /external_packages/audiodefs.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright (c) Microsoft Corporation. All rights reserved. 4 | * 5 | * File: audiodefs.h 6 | * Content: Basic constants and data types for audio work. 7 | * 8 | * Remarks: This header file defines all of the audio format constants and 9 | * structures required for XAudio2 and XACT work. Providing these 10 | * in a single location avoids certain dependency problems in the 11 | * legacy audio headers (mmreg.h, mmsystem.h, ksmedia.h). 12 | * 13 | * NOTE: Including the legacy headers after this one may cause a 14 | * compilation error, because they define some of the same types 15 | * defined here without preprocessor guards to avoid multiple 16 | * definitions. If a source file needs one of the old headers, 17 | * it must include it before including audiodefs.h. 18 | * 19 | ***************************************************************************/ 20 | 21 | #ifndef __AUDIODEFS_INCLUDED__ 22 | #define __AUDIODEFS_INCLUDED__ 23 | 24 | #include // For WORD, DWORD, etc. 25 | 26 | #pragma pack(push, 1) // Pack structures to 1-byte boundaries 27 | 28 | 29 | /************************************************************************** 30 | * 31 | * WAVEFORMATEX: Base structure for many audio formats. Format-specific 32 | * extensions can be defined for particular formats by using a non-zero 33 | * cbSize value and adding extra fields to the end of this structure. 34 | * 35 | ***************************************************************************/ 36 | 37 | #ifndef _WAVEFORMATEX_ 38 | 39 | #define _WAVEFORMATEX_ 40 | typedef struct tWAVEFORMATEX 41 | { 42 | WORD wFormatTag; // Integer identifier of the format 43 | WORD nChannels; // Number of audio channels 44 | DWORD nSamplesPerSec; // Audio sample rate 45 | DWORD nAvgBytesPerSec; // Bytes per second (possibly approximate) 46 | WORD nBlockAlign; // Size in bytes of a sample block (all channels) 47 | WORD wBitsPerSample; // Size in bits of a single per-channel sample 48 | WORD cbSize; // Bytes of extra data appended to this struct 49 | } WAVEFORMATEX; 50 | 51 | #endif 52 | 53 | // Defining pointer types outside of the #if block to make sure they are 54 | // defined even if mmreg.h or mmsystem.h is #included before this file 55 | 56 | typedef WAVEFORMATEX *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX; 57 | typedef const WAVEFORMATEX *PCWAVEFORMATEX, *LPCWAVEFORMATEX; 58 | 59 | 60 | /************************************************************************** 61 | * 62 | * WAVEFORMATEXTENSIBLE: Extended version of WAVEFORMATEX that should be 63 | * used as a basis for all new audio formats. The format tag is replaced 64 | * with a GUID, allowing new formats to be defined without registering a 65 | * format tag with Microsoft. There are also new fields that can be used 66 | * to specify the spatial positions for each channel and the bit packing 67 | * used for wide samples (e.g. 24-bit PCM samples in 32-bit containers). 68 | * 69 | ***************************************************************************/ 70 | 71 | #ifndef _WAVEFORMATEXTENSIBLE_ 72 | 73 | #define _WAVEFORMATEXTENSIBLE_ 74 | typedef struct 75 | { 76 | WAVEFORMATEX Format; // Base WAVEFORMATEX data 77 | union 78 | { 79 | WORD wValidBitsPerSample; // Valid bits in each sample container 80 | WORD wSamplesPerBlock; // Samples per block of audio data; valid 81 | // if wBitsPerSample=0 (but rarely used). 82 | WORD wReserved; // Zero if neither case above applies. 83 | } Samples; 84 | DWORD dwChannelMask; // Positions of the audio channels 85 | GUID SubFormat; // Format identifier GUID 86 | } WAVEFORMATEXTENSIBLE; 87 | 88 | #endif 89 | 90 | typedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE; 91 | typedef const WAVEFORMATEXTENSIBLE *PCWAVEFORMATEXTENSIBLE, *LPCWAVEFORMATEXTENSIBLE; 92 | 93 | 94 | 95 | /************************************************************************** 96 | * 97 | * Define the most common wave format tags used in WAVEFORMATEX formats. 98 | * 99 | ***************************************************************************/ 100 | 101 | #ifndef WAVE_FORMAT_PCM // Pulse Code Modulation 102 | 103 | // If WAVE_FORMAT_PCM is not defined, we need to define some legacy types 104 | // for compatibility with the Windows mmreg.h / mmsystem.h header files. 105 | 106 | // Old general format structure (information common to all formats) 107 | typedef struct waveformat_tag 108 | { 109 | WORD wFormatTag; 110 | WORD nChannels; 111 | DWORD nSamplesPerSec; 112 | DWORD nAvgBytesPerSec; 113 | WORD nBlockAlign; 114 | } WAVEFORMAT, *PWAVEFORMAT, NEAR *NPWAVEFORMAT, FAR *LPWAVEFORMAT; 115 | 116 | // Specific format structure for PCM data 117 | typedef struct pcmwaveformat_tag 118 | { 119 | WAVEFORMAT wf; 120 | WORD wBitsPerSample; 121 | } PCMWAVEFORMAT, *PPCMWAVEFORMAT, NEAR *NPPCMWAVEFORMAT, FAR *LPPCMWAVEFORMAT; 122 | 123 | #define WAVE_FORMAT_PCM 0x0001 124 | 125 | #endif 126 | 127 | #ifndef WAVE_FORMAT_ADPCM // Microsoft Adaptive Differental PCM 128 | 129 | // Replicate the Microsoft ADPCM type definitions from mmreg.h. 130 | 131 | typedef struct adpcmcoef_tag 132 | { 133 | short iCoef1; 134 | short iCoef2; 135 | } ADPCMCOEFSET; 136 | 137 | #pragma warning(push) 138 | #pragma warning(disable:4200) // Disable zero-sized array warnings 139 | 140 | typedef struct adpcmwaveformat_tag { 141 | WAVEFORMATEX wfx; 142 | WORD wSamplesPerBlock; 143 | WORD wNumCoef; 144 | ADPCMCOEFSET aCoef[]; // Always 7 coefficient pairs for MS ADPCM 145 | } ADPCMWAVEFORMAT; 146 | 147 | #pragma warning(pop) 148 | 149 | #define WAVE_FORMAT_ADPCM 0x0002 150 | 151 | #endif 152 | 153 | // Other frequently used format tags 154 | 155 | #ifndef WAVE_FORMAT_UNKNOWN 156 | #define WAVE_FORMAT_UNKNOWN 0x0000 // Unknown or invalid format tag 157 | #endif 158 | 159 | #ifndef WAVE_FORMAT_IEEE_FLOAT 160 | #define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point 161 | #endif 162 | 163 | #ifndef WAVE_FORMAT_MPEGLAYER3 164 | #define WAVE_FORMAT_MPEGLAYER3 0x0055 // ISO/MPEG Layer3 165 | #endif 166 | 167 | #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF 168 | #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 // Dolby Audio Codec 3 over S/PDIF 169 | #endif 170 | 171 | #ifndef WAVE_FORMAT_WMAUDIO2 172 | #define WAVE_FORMAT_WMAUDIO2 0x0161 // Windows Media Audio 173 | #endif 174 | 175 | #ifndef WAVE_FORMAT_WMAUDIO3 176 | #define WAVE_FORMAT_WMAUDIO3 0x0162 // Windows Media Audio Pro 177 | #endif 178 | 179 | #ifndef WAVE_FORMAT_WMASPDIF 180 | #define WAVE_FORMAT_WMASPDIF 0x0164 // Windows Media Audio over S/PDIF 181 | #endif 182 | 183 | #ifndef WAVE_FORMAT_EXTENSIBLE 184 | #define WAVE_FORMAT_EXTENSIBLE 0xFFFE // All WAVEFORMATEXTENSIBLE formats 185 | #endif 186 | 187 | 188 | /************************************************************************** 189 | * 190 | * Define the most common wave format GUIDs used in WAVEFORMATEXTENSIBLE 191 | * formats. Note that including the Windows ksmedia.h header after this 192 | * one will cause build problems; this cannot be avoided, since ksmedia.h 193 | * defines these macros without preprocessor guards. 194 | * 195 | ***************************************************************************/ 196 | 197 | #ifdef __cplusplus // uuid() and __uuidof() are only available in C++ 198 | 199 | #ifndef KSDATAFORMAT_SUBTYPE_PCM 200 | struct __declspec(uuid("00000001-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_PCM_STRUCT; 201 | #define KSDATAFORMAT_SUBTYPE_PCM __uuidof(KSDATAFORMAT_SUBTYPE_PCM_STRUCT) 202 | #endif 203 | 204 | #ifndef KSDATAFORMAT_SUBTYPE_ADPCM 205 | struct __declspec(uuid("00000002-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT; 206 | #define KSDATAFORMAT_SUBTYPE_ADPCM __uuidof(KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT) 207 | #endif 208 | 209 | #ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT 210 | struct __declspec(uuid("00000003-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT; 211 | #define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT __uuidof(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT) 212 | #endif 213 | 214 | #endif 215 | 216 | 217 | /************************************************************************** 218 | * 219 | * Speaker positions used in the WAVEFORMATEXTENSIBLE dwChannelMask field. 220 | * 221 | ***************************************************************************/ 222 | 223 | #ifndef SPEAKER_FRONT_LEFT 224 | #define SPEAKER_FRONT_LEFT 0x00000001 225 | #define SPEAKER_FRONT_RIGHT 0x00000002 226 | #define SPEAKER_FRONT_CENTER 0x00000004 227 | #define SPEAKER_LOW_FREQUENCY 0x00000008 228 | #define SPEAKER_BACK_LEFT 0x00000010 229 | #define SPEAKER_BACK_RIGHT 0x00000020 230 | #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040 231 | #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080 232 | #define SPEAKER_BACK_CENTER 0x00000100 233 | #define SPEAKER_SIDE_LEFT 0x00000200 234 | #define SPEAKER_SIDE_RIGHT 0x00000400 235 | #define SPEAKER_TOP_CENTER 0x00000800 236 | #define SPEAKER_TOP_FRONT_LEFT 0x00001000 237 | #define SPEAKER_TOP_FRONT_CENTER 0x00002000 238 | #define SPEAKER_TOP_FRONT_RIGHT 0x00004000 239 | #define SPEAKER_TOP_BACK_LEFT 0x00008000 240 | #define SPEAKER_TOP_BACK_CENTER 0x00010000 241 | #define SPEAKER_TOP_BACK_RIGHT 0x00020000 242 | #define SPEAKER_RESERVED 0x7FFC0000 243 | #define SPEAKER_ALL 0x80000000 244 | #define _SPEAKER_POSITIONS_ 245 | #endif 246 | 247 | #ifndef SPEAKER_STEREO 248 | #define SPEAKER_MONO (SPEAKER_FRONT_CENTER) 249 | #define SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT) 250 | #define SPEAKER_2POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY) 251 | #define SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER) 252 | #define SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) 253 | #define SPEAKER_4POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) 254 | #define SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) 255 | #define SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER) 256 | #define SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT) 257 | #define SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT) 258 | #endif 259 | 260 | 261 | #pragma pack(pop) 262 | 263 | #endif // #ifndef __AUDIODEFS_INCLUDED__ 264 | -------------------------------------------------------------------------------- /external_packages/comdecl.h: -------------------------------------------------------------------------------- 1 | // comdecl.h: Macros to facilitate COM interface and GUID declarations. 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | 4 | #ifndef _COMDECL_H_ 5 | #define _COMDECL_H_ 6 | 7 | #ifndef _XBOX 8 | #include // For standard COM interface macros 9 | #else 10 | #pragma warning(push) 11 | #pragma warning(disable:4061) 12 | #include // Required by xobjbase.h 13 | #include // Special definitions for Xbox build 14 | #pragma warning(pop) 15 | #endif 16 | 17 | // The DEFINE_CLSID() and DEFINE_IID() macros defined below allow COM GUIDs to 18 | // be declared and defined in such a way that clients can obtain the GUIDs using 19 | // either the __uuidof() extension or the old-style CLSID_Foo / IID_IFoo names. 20 | // If using the latter approach, the client can also choose whether to get the 21 | // GUID definitions by defining the INITGUID preprocessor constant or by linking 22 | // to a GUID library. This works in either C or C++. 23 | 24 | #ifdef __cplusplus 25 | 26 | #define DECLSPEC_UUID_WRAPPER(x) __declspec(uuid(#x)) 27 | #ifdef INITGUID 28 | 29 | #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 30 | class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \ 31 | EXTERN_C const GUID DECLSPEC_SELECTANY CLSID_##className = __uuidof(className) 32 | 33 | #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 34 | interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \ 35 | EXTERN_C const GUID DECLSPEC_SELECTANY IID_##interfaceName = __uuidof(interfaceName) 36 | 37 | #else // INITGUID 38 | 39 | #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 40 | class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \ 41 | EXTERN_C const GUID CLSID_##className 42 | 43 | #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 44 | interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \ 45 | EXTERN_C const GUID IID_##interfaceName 46 | 47 | #endif // INITGUID 48 | 49 | #else // __cplusplus 50 | 51 | #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 52 | DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) 53 | 54 | #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 55 | DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) 56 | 57 | #endif // __cplusplus 58 | 59 | #endif // #ifndef _COMDECL_H_ 60 | -------------------------------------------------------------------------------- /vsthost/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/vsthost/resource.h -------------------------------------------------------------------------------- /vsthost/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // vsthost.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /vsthost/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "../external_packages/aeffect.h" 28 | #include "../external_packages/aeffectx.h" 29 | 30 | #if defined _M_IX86 31 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 32 | #elif defined _M_IA64 33 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 34 | #elif defined _M_X64 35 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 36 | #else 37 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 38 | #endif 39 | 40 | typedef AEffect * (*main_func)(audioMasterCallback audioMaster); 41 | 42 | template 43 | static void append_be( std::vector & out, const T & value ) 44 | { 45 | union 46 | { 47 | T original; 48 | uint8_t raw[sizeof(T)]; 49 | } carriage; 50 | carriage.original = value; 51 | for ( unsigned i = 0; i < sizeof(T); ++i ) 52 | { 53 | out.push_back( carriage.raw[ sizeof(T) - 1 - i ] ); 54 | } 55 | } 56 | 57 | template 58 | static void retrieve_be( T & out, const uint8_t * & in, unsigned & size ) 59 | { 60 | if ( size < sizeof(T) ) return; 61 | 62 | size -= sizeof(T); 63 | 64 | union 65 | { 66 | T original; 67 | uint8_t raw[sizeof(T)]; 68 | } carriage; 69 | for ( unsigned i = 0; i < sizeof(T); ++i ) 70 | { 71 | carriage.raw[ sizeof(T) - 1 - i ] = *in++; 72 | } 73 | 74 | out = carriage.original; 75 | } 76 | -------------------------------------------------------------------------------- /vsthost/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | #define _WIN32_WINNT 0x0501 10 | 11 | #include 12 | -------------------------------------------------------------------------------- /vsthost/vsthost.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/vsthost/vsthost.ico -------------------------------------------------------------------------------- /vsthost/vsthost.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkammueller/vstdriver/767eeb25bac1852a10e4c871329f322076df06cc/vsthost/vsthost.rc -------------------------------------------------------------------------------- /vsthost/vsthost.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vsthost", "vsthost.vcxproj", "{5D666F11-5E76-4653-8B5B-32988E4907A0}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Debug|Win32.Build.0 = Debug|Win32 16 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Debug|x64.ActiveCfg = Debug|x64 17 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Debug|x64.Build.0 = Debug|x64 18 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Release|Win32.ActiveCfg = Release|Win32 19 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Release|Win32.Build.0 = Release|Win32 20 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Release|x64.ActiveCfg = Release|x64 21 | {5D666F11-5E76-4653-8B5B-32988E4907A0}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /vsthost/vsthost.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {5D666F11-5E76-4653-8B5B-32988E4907A0} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | Win32Proj 32 | vsthost 33 | 34 | 35 | 36 | Application 37 | true 38 | Unicode 39 | 40 | 41 | Application 42 | true 43 | Unicode 44 | 45 | 46 | Application 47 | false 48 | true 49 | Unicode 50 | 51 | 52 | Application 53 | false 54 | true 55 | Unicode 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Use 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | MultiThreadedDebug 92 | 93 | 94 | Windows 95 | true 96 | comctl32.lib;%(AdditionalDependencies) 97 | ../output/vsthost32.exe 98 | 99 | 100 | 101 | 102 | Use 103 | Level3 104 | Disabled 105 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | MultiThreadedDebug 107 | 108 | 109 | Windows 110 | true 111 | comctl32.lib;%(AdditionalDependencies) 112 | ../output/64/vsthost64.exe 113 | 114 | 115 | 116 | 117 | Level3 118 | Use 119 | MinSpace 120 | true 121 | true 122 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | MultiThreaded 124 | Fast 125 | 126 | 127 | Windows 128 | true 129 | true 130 | true 131 | comctl32.lib;%(AdditionalDependencies) 132 | ../output/vsthost32.exe 133 | 134 | 135 | 136 | 137 | Level3 138 | Use 139 | MinSpace 140 | true 141 | true 142 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | MultiThreaded 144 | Fast 145 | 146 | 147 | Windows 148 | true 149 | true 150 | true 151 | comctl32.lib;%(AdditionalDependencies) 152 | ../output/64/vsthost64.exe 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | Create 163 | Create 164 | Create 165 | Create 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /vsthost/vsthost.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | 37 | 38 | Resource Files 39 | 40 | 41 | 42 | 43 | Resource Files 44 | 45 | 46 | -------------------------------------------------------------------------------- /vstmididrv.nsi: -------------------------------------------------------------------------------- 1 | !include "x64.nsh" 2 | !include MUI2.nsh 3 | !include WinVer.nsh 4 | ; The name of the installer 5 | Name "VST MIDI System Synth" 6 | 7 | ; The file to write 8 | OutFile "vstmididrv.exe" 9 | ; Request application privileges for Windows Vista 10 | RequestExecutionLevel admin 11 | SetCompressor /solid lzma 12 | ;-------------------------------- 13 | ; Pages 14 | !insertmacro MUI_PAGE_WELCOME 15 | Page Custom LockedListShow 16 | !insertmacro MUI_PAGE_INSTFILES 17 | UninstPage Custom un.LockedListShow 18 | !insertmacro MUI_UNPAGE_CONFIRM 19 | !insertmacro MUI_UNPAGE_INSTFILES 20 | !insertmacro MUI_LANGUAGE "English" 21 | 22 | !macro DeleteOnReboot Path 23 | IfFileExists `${Path}` 0 +3 24 | SetFileAttributes `${Path}` NORMAL 25 | Delete /rebootok `${Path}` 26 | !macroend 27 | !define DeleteOnReboot `!insertmacro DeleteOnReboot` 28 | 29 | Function LockedListShow 30 | ${If} ${AtLeastWinVista} 31 | !insertmacro MUI_HEADER_TEXT `File in use check` `Drive use check` 32 | LockedList::AddModule \vstmididrv.dll 33 | LockedList::Dialog /autonext 34 | Pop $R0 35 | ${EndIf} 36 | FunctionEnd 37 | Function un.LockedListShow 38 | ${If} ${AtLeastWinVista} 39 | !insertmacro MUI_HEADER_TEXT `File in use check` `Drive use check` 40 | LockedList::AddModule \vstmididrv.dll 41 | LockedList::Dialog /autonext 42 | Pop $R0 43 | ${EndIf} 44 | FunctionEnd 45 | ;-------------------------------- 46 | Function .onInit 47 | ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" "UninstallString" 48 | StrCmp $R0 "" done 49 | MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ 50 | "The MIDI driver is already installed. $\n$\nClick `OK` to remove the \ 51 | previous version or `Cancel` to cancel this upgrade." \ 52 | IDOK uninst 53 | Abort 54 | ;Run the uninstaller 55 | uninst: 56 | ClearErrors 57 | Exec $R0 58 | Abort 59 | done: 60 | MessageBox MB_YESNO "This will install the VST MIDI System Synth. Continue?" IDYES NoAbort 61 | Abort ; causes installer to quit. 62 | NoAbort: 63 | FunctionEnd 64 | ; The stuff to install 65 | Section "Needed (required)" 66 | SectionIn RO 67 | ; Copy files according to whether its x64 or not. 68 | DetailPrint "Copying driver and synth..." 69 | ${If} ${RunningX64} 70 | SetOutPath $WINDIR\SysWow64 71 | File output\vstmididrv.dll 72 | File output\vstmididrvcfg.exe 73 | File output\vsthost32.exe 74 | File output\64\vsthost64.exe 75 | SetOutPath $WINDIR\SysNative 76 | File output\64\vstmididrv.dll 77 | File output\vsthost32.exe 78 | File output\64\vsthost64.exe 79 | ;check if already installed 80 | StrCpy $1 "0" 81 | LOOP1: 82 | ;k not installed, do checks 83 | IntOp $1 $1 + 1 84 | ClearErrors 85 | ReadRegStr $0 HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "midi$1" 86 | StrCmp $0 "" INSTALLDRIVER1 NEXTCHECK1 87 | NEXTCHECK1: 88 | StrCmp $0 "wdmaud.drv" 0 NEXT1 89 | INSTALLDRIVER1: 90 | WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "midi$1" "vstmididrv.dll" 91 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 92 | "MIDI" "midi$1" 93 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 94 | "MIDIDRV" "$0" 95 | Goto REGDONE1 96 | NEXT1: 97 | StrCmp $1 "9" 0 LOOP1 98 | REGDONE1: 99 | ;check if 64-bit already installed 100 | SetRegView 64 101 | StrCpy $1 "0" 102 | LOOP2: 103 | ;k not installed, do checks 104 | IntOp $1 $1 + 1 105 | ClearErrors 106 | ReadRegStr $0 HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "midi$1" 107 | StrCmp $0 "" INSTALLDRIVER2 NEXTCHECK2 108 | NEXTCHECK2: 109 | StrCmp $0 "wdmaud.drv" 0 NEXT2 110 | INSTALLDRIVER2: 111 | WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "midi$1" "vstmididrv.dll" 112 | SetRegView 32 113 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 114 | "MIDI64" "midi$1" 115 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 116 | "MIDIDRV64" "$0" 117 | Goto REGDONE2 118 | NEXT2: 119 | StrCmp $1 "9" 0 LOOP2 120 | REGDONE2: 121 | ${Else} 122 | SetOutPath $WINDIR\System32 123 | File output\vstmididrv.dll 124 | File output\vstmididrvcfg.exe 125 | File output\vsthost32.exe 126 | 127 | ;check if already installed 128 | StrCpy $1 "0" 129 | LOOP3: 130 | ;k not installed, do checks 131 | IntOp $1 $1 + 1 132 | ClearErrors 133 | ReadRegStr $0 HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "midi$1" 134 | StrCmp $0 "" INSTALLDRIVER3 NEXTCHECK3 135 | NEXTCHECK3: 136 | StrCmp $0 "wdmaud.drv" 0 NEXT3 137 | INSTALLDRIVER3: 138 | WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "midi$1" "vstmididrv.dll" 139 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 140 | "MIDI" "midi$1" 141 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 142 | "MIDIDRV" "$0" 143 | Goto REGDONE3 144 | NEXT3: 145 | StrCmp $1 "9" 0 LOOP3 146 | REGDONE3: 147 | ${EndIf} 148 | 149 | ; Write the uninstall keys 150 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" "DisplayName" "VST MIDI System Synth" 151 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" "NoModify" 1 152 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" "NoRepair" 1 153 | CreateDirectory "$SMPROGRAMS\VST MIDI System Synth" 154 | ${If} ${RunningX64} 155 | WriteUninstaller "$WINDIR\SysWow64\vstmididrvuninstall.exe" 156 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" "UninstallString" '"$WINDIR\SysWow64\vstmididrvuninstall.exe"' 157 | CreateShortCut "$SMPROGRAMS\VST MIDI System Synth\Uninstall.lnk" "$WINDIR\SysWow64\vstmididrvuninstall.exe" "" "$WINDIR\SysWow64\vstmididrvuninstall.exe" 0 158 | CreateShortCut "$SMPROGRAMS\VST MIDI System Synth\Configure Driver.lnk" "$WINDIR\SysWow64\vstmididrvcfg.exe" "" "$WINDIR\SysWow64\vstmididrvcfg.exe" 0 159 | ${Else} 160 | WriteUninstaller "$WINDIR\System32\vstmididrvuninstall.exe" 161 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" "UninstallString" '"$WINDIR\System32\vstmididrvuninstall.exe"' 162 | CreateShortCut "$SMPROGRAMS\VST MIDI System Synth\Uninstall.lnk" "$WINDIR\System32\vstmididrvuninstall.exe" "" "$WINDIR\System32\vstmididrvuninstall.exe" 0 163 | CreateShortCut "$SMPROGRAMS\VST MIDI System Synth\Configure Driver.lnk" "$WINDIR\System32\vstmididrvcfg.exe" "" "$WINDIR\System32\vstmididrvcfg.exe" 0 164 | ${EndIf} 165 | MessageBox MB_OK "Installation complete! Use the driver configuration tool which is in the 'VST MIDI System Synth' program shortcut directory to configure the driver." 166 | 167 | SectionEnd 168 | ;-------------------------------- 169 | ; Uninstaller 170 | Section "Uninstall" 171 | ; Remove registry keys 172 | ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 173 | "MIDI" 174 | ReadRegStr $1 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 175 | "MIDIDRV" 176 | WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "$0" "$1" 177 | DeleteRegKey HKCU "Software\VST MIDI Driver" 178 | RMDir /r "$SMPROGRAMS\VST MIDI System Synth" 179 | ${If} ${RunningX64} 180 | ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 181 | "MIDI64" 182 | ReadRegStr $1 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth\Backup" \ 183 | "MIDIDRV64" 184 | SetRegView 64 185 | WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\Drivers32" "$0" "$1" 186 | SetRegView 32 187 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" 188 | ${If} ${AtLeastWinVista} 189 | Delete $WINDIR\SysWow64\vstmididrv.dll 190 | Delete $WINDIR\SysWow64\vstmididrvuninstall.exe 191 | Delete $WINDIR\SysWow64\vstmididrvcfg.exe 192 | Delete $WINDIR\SysNative\vstmididrv.dll 193 | Delete $WINDIR\SysNative\vstmididrvcfg.exe 194 | ${Else} 195 | MessageBox MB_OK "Note: The uninstaller will reboot your system to remove drivers." 196 | ${DeleteOnReboot} $WINDIR\SysWow64\vstmididrv.dll 197 | ${DeleteOnReboot} $WINDIR\SysWow64\vstmididrvuninstall.exe 198 | ${DeleteOnReboot} $WINDIR\SysWow64\vstmididrvcfg.exe 199 | Reboot 200 | ${Endif} 201 | ${Else} 202 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VST MIDI System Synth" 203 | ${If} ${AtLeastWinVista} 204 | Delete $WINDIR\System32\vstmididrv.dll 205 | Delete $WINDIR\System32\vstmidiuninstall.exe 206 | Delete $WINDIR\System32\vstmidicfg.exe 207 | ${Else} 208 | MessageBox MB_OK "Note: The uninstaller will reboot your system to remove drivers." 209 | ${DeleteOnReboot} $WINDIR\System32\vstmididrv.dll 210 | ${DeleteOnReboot} $WINDIR\System32\vstmididrvuninstall.exe 211 | ${DeleteOnReboot} $WINDIR\System32\vstmididrvcfg.exe 212 | Reboot 213 | ${Endif} 214 | ${EndIf} 215 | SectionEnd 216 | --------------------------------------------------------------------------------