truelight@0: /********************************************************************* truelight@0: * OpenTTD: An Open Source Transport Tycoon Deluxe clone * truelight@0: * Copyright (c) 2002-2004 OpenTTD Developers. All Rights Reserved. * truelight@0: * * truelight@0: * Web site: http://openttd.sourceforge.net/ * truelight@0: *********************************************************************/ truelight@0: truelight@0: /* truelight@0: * This program is free software; you can redistribute it and/or modify truelight@0: * it under the terms of the GNU General Public License as published by truelight@0: * the Free Software Foundation; either version 2 of the License, or truelight@0: * (at your option) any later version. truelight@0: * truelight@0: * This program is distributed in the hope that it will be useful, truelight@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of truelight@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the truelight@0: * GNU General Public License for more details. truelight@0: * truelight@0: * You should have received a copy of the GNU General Public License truelight@0: * along with this program; if not, write to the Free Software truelight@0: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. truelight@0: */ truelight@0: truelight@0: /* DirectMusic driver for Win32 */ truelight@0: /* Based on dxmci from TTDPatch */ truelight@0: truelight@0: #include "stdafx.h" truelight@0: truelight@0: #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT truelight@0: truelight@0: // for gcc, the GUIDs are available in a library instead truelight@0: #ifndef __GNUC__ truelight@0: #define INITGUID truelight@0: #endif truelight@0: truelight@0: #ifdef __cplusplus truelight@0: extern "C" { truelight@0: #endif truelight@0: truelight@0: #include "ttd.h" truelight@0: #include "sound.h" truelight@0: #include "hal.h" truelight@0: truelight@0: #ifdef __cplusplus truelight@0: } truelight@0: #endif truelight@0: truelight@0: #include truelight@0: #include truelight@0: truelight@0: #include truelight@0: #include truelight@0: #include truelight@0: #include truelight@0: truelight@0: #define VARIANT int truelight@0: truelight@0: #define MSGBOX(output) DEBUG(misc, 0) ("DirectMusic driver: %s\n", output); //MessageBox(NULL, output, "dxmci",MB_OK); truelight@0: #define MULTI_TO_WIDE( x,y ) MultiByteToWideChar( CP_ACP,MB_PRECOMPOSED, y,-1,x,_MAX_PATH); truelight@0: truelight@0: // the performance object controls manipulation of the segments truelight@0: IDirectMusicPerformance *performance = NULL; truelight@0: truelight@0: // the segment object is where the MIDI data is stored for playback truelight@0: IDirectMusicSegment *segment = NULL; truelight@0: truelight@0: // the loader bject can load many types of DMusic related files truelight@193: IDirectMusicLoader *loader = NULL; truelight@0: truelight@0: // whether we've initialized COM or not (when deciding whether to shut down) truelight@0: int COMInitialized = 0; truelight@0: truelight@0: truelight@0: extern "C" bool LoadLibraryList(void **proc, const char *dll); truelight@0: truelight@0: // Use lazy linking truelight@0: struct ProcPtrs { truelight@0: unsigned long (WINAPI *CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv); truelight@0: HRESULT (WINAPI *CoInitialize)( LPVOID pvReserved ); truelight@0: void (WINAPI *CoUninitialize)( ); truelight@0: }; truelight@0: truelight@0: #define M(x) x "\0" truelight@193: static const char ole_files[] = truelight@0: M("ole32.dll") truelight@0: M("CoCreateInstance") truelight@0: M("CoInitialize") truelight@0: M("CoUninitialize") truelight@0: M("") truelight@0: ; truelight@0: #undef M truelight@0: truelight@0: truelight@0: static ProcPtrs _proc; truelight@0: truelight@0: static bool LoadOleDLL() truelight@0: { truelight@193: if (_proc.CoCreateInstance != NULL) truelight@0: return true; truelight@0: if (!LoadLibraryList((void**)&_proc, ole_files)) truelight@0: return false; truelight@0: return true; truelight@0: } truelight@0: truelight@0: truelight@0: #ifdef __cplusplus truelight@0: extern "C" { truelight@0: #endif truelight@0: truelight@0: // Initialize COM and DirectMusic truelight@0: bool InitDirectMusic (void) truelight@0: { truelight@0: if (NULL != performance) truelight@0: return true; truelight@0: truelight@0: // Initialize COM truelight@0: if (!COMInitialized) { truelight@0: if (!LoadOleDLL()) { truelight@0: MSGBOX("ole32.dll load failed"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: _proc.CoInitialize(NULL); truelight@0: COMInitialized = 1; truelight@0: } truelight@0: truelight@0: // Create the performance object via CoCreateInstance truelight@0: if (FAILED(_proc.CoCreateInstance( truelight@0: (REFCLSID)CLSID_DirectMusicPerformance, truelight@0: NULL, truelight@0: CLSCTX_INPROC, truelight@0: (REFIID)IID_IDirectMusicPerformance, truelight@0: (LPVOID *)&performance))) { truelight@0: MSGBOX ("Failed to create the performance object"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // Initialize it truelight@0: if (FAILED(performance->Init(NULL, NULL, NULL))) { truelight@0: MSGBOX("Failed to initialize performance object"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // Choose default Windows synth truelight@0: if (FAILED(performance->AddPort (NULL))) { truelight@0: MSGBOX("AddPort failed"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // now we'll create the loader object. This will be used to load the truelight@0: // midi file for our demo. Again, we need to use CoCreateInstance truelight@0: // and pass the appropriate ID parameters truelight@0: if (FAILED(_proc.CoCreateInstance((REFCLSID)CLSID_DirectMusicLoader, truelight@193: NULL, CLSCTX_INPROC, truelight@0: (REFIID)IID_IDirectMusicLoader, truelight@0: (LPVOID *)&loader))) { truelight@0: MSGBOX("Failed to create loader object"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // that's it for initialization. If we made it this far we truelight@0: // were successful. truelight@0: return true; truelight@0: } truelight@0: truelight@193: // Releases memory used by all of the initialized truelight@0: // DirectMusic objects in the program truelight@0: void ReleaseSegment (void) truelight@0: { truelight@0: if (NULL != segment) { truelight@0: segment->Release (); truelight@0: segment = NULL; truelight@0: } truelight@0: } truelight@0: void ShutdownDirectMusic (void) truelight@0: { truelight@193: // release everything but the segment, which the performance truelight@193: // will release automatically (and it'll crash if it's been truelight@0: // released already) truelight@0: truelight@0: if (NULL != loader) { truelight@0: loader->Release (); truelight@0: loader = NULL; truelight@0: } truelight@0: truelight@0: if (NULL != performance) truelight@0: { truelight@0: performance->CloseDown (); truelight@0: performance->Release (); truelight@0: performance = NULL; truelight@0: } truelight@0: truelight@0: if (COMInitialized) { truelight@0: _proc.CoUninitialize(); truelight@0: COMInitialized = 0; truelight@0: } truelight@0: } truelight@0: truelight@193: // Load MIDI file for playing truelight@0: bool LoadMIDI (char *directory, char *filename) truelight@0: { truelight@0: DMUS_OBJECTDESC obj_desc; truelight@0: WCHAR w_directory[_MAX_PATH]; // utf-16 version of the directory name. truelight@0: WCHAR w_filename[_MAX_PATH]; // utf-16 version of the file name truelight@0: truelight@0: if (NULL == performance) truelight@0: return false; truelight@0: truelight@0: MULTI_TO_WIDE(w_directory,directory); truelight@0: truelight@0: if (FAILED(loader->SetSearchDirectory((REFGUID) GUID_DirectMusicAllTypes, truelight@0: w_directory, FALSE))) { truelight@0: MSGBOX("LoadMIDI: SetSearchDirectory failed"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // set up the loader object info truelight@0: ZeroMemory (&obj_desc, sizeof (obj_desc)); truelight@0: obj_desc.dwSize = sizeof (obj_desc); truelight@0: truelight@0: MULTI_TO_WIDE(w_filename,filename); truelight@0: obj_desc.guidClass = CLSID_DirectMusicSegment; truelight@0: truelight@0: wcscpy (obj_desc.wszFileName,w_filename); truelight@0: obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME; truelight@0: truelight@0: // release the existing segment if we have any truelight@0: if (NULL != segment) truelight@0: ReleaseSegment(); truelight@0: truelight@0: // and make a new segment truelight@193: if (FAILED(loader->GetObject(&obj_desc, truelight@193: (REFIID)IID_IDirectMusicSegment, truelight@0: (LPVOID *) &segment))) { truelight@0: MSGBOX("LoadMIDI: Get object failed"); truelight@0: return FALSE; truelight@0: } truelight@0: truelight@0: // next we need to tell the segment what kind of data it contains. We do this truelight@0: // with the IDirectMusicSegment::SetParam function. truelight@0: if (FAILED(segment->SetParam((REFGUID)GUID_StandardMIDIFile, truelight@0: -1, 0, 0, (LPVOID)performance))) { truelight@0: MSGBOX("LoadMIDI: SetParam (MIDI file) failed"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // finally, we need to tell the segment to 'download' the instruments truelight@0: if (FAILED(segment->SetParam((REFGUID)GUID_Download, truelight@0: -1, 0, 0, (LPVOID)performance))) { truelight@0: MSGBOX("LoadMIDI: Failed to download instruments"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // at this point, the MIDI file is loaded and ready to play! truelight@0: return true; truelight@0: } truelight@0: truelight@0: // Start playing the MIDI file truelight@0: void PlaySegment (void) truelight@0: { truelight@0: if (NULL == performance) truelight@0: return; truelight@0: truelight@0: if (FAILED(performance->PlaySegment(segment, 0, 0, NULL))) { truelight@0: MSGBOX("PlaySegment failed"); truelight@0: } truelight@0: } truelight@0: truelight@0: // Stop playing truelight@0: void StopSegment (void) truelight@0: { truelight@0: if (NULL == performance || NULL == segment) truelight@0: return; truelight@0: truelight@0: if (FAILED(performance->Stop(segment, NULL, 0, 0))) { truelight@0: MSGBOX("StopSegment failed"); truelight@0: } truelight@0: } truelight@0: truelight@0: // Find out whether playing has started or stopped truelight@0: bool IsSegmentPlaying (void) truelight@0: { truelight@0: if (NULL == performance || NULL == segment) truelight@0: return FALSE; truelight@0: truelight@0: // IsPlaying return S_OK if the segment is currently playing truelight@0: return performance->IsPlaying(segment, NULL) == S_OK ? TRUE : FALSE; truelight@0: } truelight@0: truelight@0: void SetVolume(long vol) truelight@0: { truelight@0: long db; truelight@0: truelight@0: if (performance == NULL && !InitDirectMusic()) truelight@0: return; truelight@0: truelight@0: db = ((vol >> 21) & 0x7ff) - 1000; truelight@0: performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db)); truelight@0: } truelight@0: truelight@0: #if defined(__cplusplus) truelight@0: } truelight@0: #endif truelight@0: darkvater@223: #endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */