# dmusic.cpp

Go to the documentation of this file.

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