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 */

Generated on Wed Dec 30 20:40:03 2009 for OpenTTD by  doxygen 1.5.6