# dmusic.cpp

Go to the documentation of this file.

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