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