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