dmusic.cpp

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

Generated on Wed Dec 23 20:12:48 2009 for OpenTTD by  doxygen 1.5.6