dmusic.cpp

Go to the documentation of this file.
00001 /* $Id: dmusic.cpp 20105 2010-07-09 22:25:25Z rubidium $ */
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 */

Generated on Sun Jan 9 16:01:55 2011 for OpenTTD by  doxygen 1.6.1