# dmusic.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD 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, version 2.
    00006  * OpenTTD 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.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
    00013
    00014 #include "../stdafx.h"
    00015 #ifdef WIN32_LEAN_AND_MEAN
    00016   #undef WIN32_LEAN_AND_MEAN // Don't exclude rarely-used stuff from Windows headers
    00017 #endif
    00018 #include "../debug.h"
    00019 #include "../os/windows/win32.h"
    00020 #include "dmusic.h"
    00021
    00022 #include <windows.h>
    00023 #include <dmksctrl.h>
    00024 #include <dmusici.h>
    00025 #include <dmusicc.h>
    00026 #include <dmusicf.h>
    00027
    00028 static FMusicDriver_DMusic iFMusicDriver_DMusic;
    00029
    00031 static IDirectMusicPerformance *performance = NULL;
    00032
    00034 static IDirectMusicLoader *loader = NULL;
    00035
    00037 static IDirectMusicSegment *segment = NULL;
    00038
    00039 static bool seeking = false;
    00040
    00041
    00042 #define M(x) x "\0"
    00043 static const char ole_files[] =
    00044   M("ole32.dll")
    00045   M("CoCreateInstance")
    00046   M("CoInitialize")
    00047   M("CoUninitialize")
    00048   M("")
    00049 ;
    00050 #undef M
    00051
    00052 struct ProcPtrs {
    00053   unsigned long (WINAPI * CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
    00054   HRESULT (WINAPI * CoInitialize)(LPVOID pvReserved);
    00055   void (WINAPI * CoUninitialize)();
    00056 };
    00057
    00058 static ProcPtrs proc;
    00059
    00060
    00061 const char *MusicDriver_DMusic::Start(const char * const *parm)
    00062 {
    00063   if (performance != NULL) return NULL;
    00064
    00065   if (proc.CoCreateInstance == NULL) {
    00066     if (!LoadLibraryList((Function*)&proc, ole_files)) {
    00067       return "ole32.dll load failed";
    00068     }
    00069   }
    00070
    00071   /* Initialize COM */
    00072   if (FAILED(proc.CoInitialize(NULL))) {
    00073     return "COM initialization failed";
    00074   }
    00075
    00076   /* create the performance object */
    00077   if (FAILED(proc.CoCreateInstance(
    00078         CLSID_DirectMusicPerformance,
    00079         NULL,
    00080         CLSCTX_INPROC,
    00081         IID_IDirectMusicPerformance,
    00082         (LPVOID*)&performance
    00083       ))) {
    00084     proc.CoUninitialize();
    00085     return "Failed to create the performance object";
    00086   }
    00087
    00088   /* initialize it */
    00089   if (FAILED(performance->Init(NULL, NULL, NULL))) {
    00090     performance->Release();
    00091     performance = NULL;
    00092     proc.CoUninitialize();
    00093     return "Failed to initialize performance object";
    00094   }
    00095
    00096   /* choose default Windows synth */
    00097   if (FAILED(performance->AddPort(NULL))) {
    00098     performance->CloseDown();
    00099     performance->Release();
    00100     performance = NULL;
    00101     proc.CoUninitialize();
    00102     return "AddPort failed";
    00103   }
    00104
    00105   /* create the loader object; this will be used to load the MIDI file */
    00106   if (FAILED(proc.CoCreateInstance(
    00107         CLSID_DirectMusicLoader,
    00108         NULL,
    00109         CLSCTX_INPROC,
    00110         IID_IDirectMusicLoader,
    00111         (LPVOID*)&loader
    00112       ))) {
    00113     performance->CloseDown();
    00114     performance->Release();
    00115     performance = NULL;
    00116     proc.CoUninitialize();
    00117     return "Failed to create loader object";
    00118   }
    00119
    00120   return NULL;
    00121 }
    00122
    00123
    00124 void MusicDriver_DMusic::Stop()
    00125 {
    00126   seeking = false;
    00127
    00128   if (performance != NULL) performance->Stop(NULL, NULL, 0, 0);
    00129
    00130   if (segment != NULL) {
    00131     segment->SetParam(GUID_Unload, 0xFFFFFFFF, 0, 0, performance);
    00132     segment->Release();
    00133     segment = NULL;
    00134   }
    00135
    00136   if (performance != NULL) {
    00137     performance->CloseDown();
    00138     performance->Release();
    00139     performance = NULL;
    00140   }
    00141
    00142   if (loader != NULL) {
    00143     loader->Release();
    00144     loader = NULL;
    00145   }
    00146
    00147   proc.CoUninitialize();
    00148 }
    00149
    00150
    00151 void MusicDriver_DMusic::PlaySong(const char *filename)
    00152 {
    00153   /* set up the loader object info */
    00154   DMUS_OBJECTDESC obj_desc;
    00155   ZeroMemory(&obj_desc, sizeof(obj_desc));
    00156   obj_desc.dwSize = sizeof(obj_desc);
    00157   obj_desc.guidClass = CLSID_DirectMusicSegment;
    00158   obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
    00159   MultiByteToWideChar(
    00160     CP_ACP, MB_PRECOMPOSED,
    00161     filename, -1,
    00162     obj_desc.wszFileName, lengthof(obj_desc.wszFileName)
    00163   );
    00164
    00165   /* release the existing segment if we have any */
    00166   if (segment != NULL) {
    00167     segment->Release();
    00168     segment = NULL;
    00169   }
    00170
    00171   /* make a new segment */
    00172   if (FAILED(loader->GetObject(
    00173         &obj_desc, IID_IDirectMusicSegment, (LPVOID*)&segment
    00174       ))) {
    00175     DEBUG(driver, 0, "DirectMusic: GetObject failed");
    00176     return;
    00177   }
    00178
    00179   /* tell the segment what kind of data it contains */
    00180   if (FAILED(segment->SetParam(
    00181         GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, performance
    00182       ))) {
    00183     DEBUG(driver, 0, "DirectMusic: SetParam (MIDI file) failed");
    00184     return;
    00185   }
    00186
    00187   /* tell the segment to 'download' the instruments */
    00188   if (FAILED(segment->SetParam(GUID_Download, 0xFFFFFFFF, 0, 0, performance))) {
    00189     DEBUG(driver, 0, "DirectMusic: failed to download instruments");
    00190     return;
    00191   }
    00192
    00193   /* start playing the MIDI file */
    00194   if (FAILED(performance->PlaySegment(segment, 0, 0, NULL))) {
    00195     DEBUG(driver, 0, "DirectMusic: PlaySegment failed");
    00196     return;
    00197   }
    00198
    00199   seeking = true;
    00200 }
    00201
    00202
    00203 void MusicDriver_DMusic::StopSong()
    00204 {
    00205   if (FAILED(performance->Stop(segment, NULL, 0, 0))) {
    00206     DEBUG(driver, 0, "DirectMusic: StopSegment failed");
    00207   }
    00208   seeking = false;
    00209 }
    00210
    00211
    00212 bool MusicDriver_DMusic::IsSongPlaying()
    00213 {
    00214   /* Not the nicest code, but there is a short delay before playing actually
    00215    * starts. OpenTTD makes no provision for this. */
    00216   if (performance->IsPlaying(segment, NULL) == S_OK) {
    00217     seeking = false;
    00218     return true;
    00219   } else {
    00220     return seeking;
    00221   }
    00222 }
    00223
    00224
    00225 void MusicDriver_DMusic::SetVolume(byte vol)
    00226 {
    00227   long db = vol * 2000 / 127 - 2000;
    00228   performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db));
    00229 }
    00230
    00231
    00232 #endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */