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: Darkvater@1891: #include "openttd.h" tron@1302: #include "debug.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: tron@2168: #define MSGBOX(output) DEBUG(misc, 0) ("DirectMusic driver: %s\n", output); //MessageBox(NULL, output, "dxmci",MB_OK); truelight@0: tron@2168: static void MultiToWide(WCHAR* to, const char* from) tron@2168: { tron@2168: MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, to, _MAX_PATH); tron@2168: } truelight@0: truelight@0: // the performance object controls manipulation of the segments tron@2168: static IDirectMusicPerformance *performance = NULL; truelight@0: truelight@0: // the segment object is where the MIDI data is stored for playback tron@2168: static IDirectMusicSegment *segment = NULL; truelight@0: truelight@0: // the loader bject can load many types of DMusic related files tron@2168: static IDirectMusicLoader *loader = NULL; truelight@0: truelight@0: // whether we've initialized COM or not (when deciding whether to shut down) tron@2168: static 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: tron@1117: static bool LoadOleDLL(void) 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 tron@2168: 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( tron@2168: CLSID_DirectMusicPerformance, tron@2168: NULL, tron@2168: CLSCTX_INPROC, tron@2168: IID_IDirectMusicPerformance, tron@2168: (LPVOID*)&performance tron@2168: ))) { tron@2168: 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 tron@2168: 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 tron@2168: if (FAILED(_proc.CoCreateInstance( tron@2168: CLSID_DirectMusicLoader, tron@2168: NULL, tron@2168: CLSCTX_INPROC, tron@2168: IID_IDirectMusicLoader, tron@2168: (LPVOID*)&loader tron@2168: ))) { 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 tron@2168: void ReleaseSegment(void) truelight@0: { truelight@0: if (NULL != segment) { tron@2168: segment->Release(); truelight@0: segment = NULL; truelight@0: } truelight@0: } tron@2168: tron@2168: 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) { tron@2168: loader->Release(); truelight@0: loader = NULL; truelight@0: } truelight@0: tron@2168: if (NULL != performance) { tron@2168: performance->CloseDown(); tron@2168: 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 tron@2168: bool LoadMIDI(const char *directory, const 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: tron@2168: MultiToWide(w_directory, directory); truelight@0: tron@2168: if (FAILED(loader->SetSearchDirectory( tron@2168: GUID_DirectMusicAllTypes, w_directory, FALSE tron@2168: ))) { truelight@0: MSGBOX("LoadMIDI: SetSearchDirectory failed"); truelight@0: return false; truelight@0: } truelight@0: truelight@0: // set up the loader object info tron@2168: ZeroMemory(&obj_desc, sizeof(obj_desc)); tron@2168: obj_desc.dwSize = sizeof(obj_desc); truelight@0: tron@2168: MultiToWide(w_filename, filename); truelight@0: obj_desc.guidClass = CLSID_DirectMusicSegment; truelight@0: tron@2168: 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 tron@2168: if (FAILED(loader->GetObject( tron@2168: &obj_desc, IID_IDirectMusicSegment, (LPVOID*)&segment tron@2168: ))) { truelight@0: MSGBOX("LoadMIDI: Get object failed"); tron@2168: 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. tron@2168: if (FAILED(segment->SetParam( tron@2168: GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, performance tron@2168: ))) { 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 tron@2168: if (FAILED(segment->SetParam(GUID_Download, 0xFFFFFFFF, 0, 0, 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 tron@2168: 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 tron@2168: 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 tron@2168: bool IsSegmentPlaying(void) truelight@0: { truelight@0: if (NULL == performance || NULL == segment) tron@2168: return false; truelight@0: truelight@0: // IsPlaying return S_OK if the segment is currently playing tron@2168: return performance->IsPlaying(segment, NULL) == S_OK; 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 */