00001
00002
00003
00004
00005
00006
00007
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 "../core/mem_func.hpp"
00022 #include "dmusic.h"
00023
00024 #include <windows.h>
00025 #include <dmksctrl.h>
00026 #include <dmusici.h>
00027 #include <dmusicc.h>
00028 #include <dmusicf.h>
00029
00030 static FMusicDriver_DMusic iFMusicDriver_DMusic;
00031
00033 static IDirectMusic *music = NULL;
00034
00036 static IDirectMusicPerformance *performance = NULL;
00037
00039 static IDirectMusicLoader *loader = NULL;
00040
00042 static IDirectMusicSegment *segment = NULL;
00043
00044 static bool seeking = false;
00045
00046
00047 #define M(x) x "\0"
00048 static const char ole_files[] =
00049 M("ole32.dll")
00050 M("CoCreateInstance")
00051 M("CoInitialize")
00052 M("CoUninitialize")
00053 M("")
00054 ;
00055 #undef M
00056
00057 struct ProcPtrs {
00058 unsigned long (WINAPI * CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
00059 HRESULT (WINAPI * CoInitialize)(LPVOID pvReserved);
00060 void (WINAPI * CoUninitialize)();
00061 };
00062
00063 static ProcPtrs proc;
00064
00065
00066 const char *MusicDriver_DMusic::Start(const char * const *parm)
00067 {
00068 if (performance != NULL) return NULL;
00069
00070 if (proc.CoCreateInstance == NULL) {
00071 if (!LoadLibraryList((Function*)&proc, ole_files)) {
00072 return "ole32.dll load failed";
00073 }
00074 }
00075
00076
00077 if (FAILED(proc.CoInitialize(NULL))) {
00078 return "COM initialization failed";
00079 }
00080
00081
00082 if (FAILED(proc.CoCreateInstance(
00083 CLSID_DirectMusicPerformance,
00084 NULL,
00085 CLSCTX_INPROC,
00086 IID_IDirectMusicPerformance,
00087 (LPVOID*)&performance
00088 ))) {
00089 return "Failed to create the performance object";
00090 }
00091
00092
00093 if (FAILED(performance->Init(&music, NULL, NULL))) {
00094 return "Failed to initialize performance object";
00095 }
00096
00097 int port = GetDriverParamInt(parm, "port", -1);
00098
00099 #ifndef NO_DEBUG_MESSAGES
00100 if (_debug_driver_level > 0) {
00101
00102 char desc[DMUS_MAX_DESCRIPTION];
00103
00104 DMUS_PORTCAPS caps;
00105 MemSetT(&caps, 0);
00106 caps.dwSize = sizeof(DMUS_PORTCAPS);
00107
00108 DEBUG(driver, 1, "Detected DirectMusic ports:");
00109 for (int i = 0; music->EnumPort(i, &caps) == S_OK; i++) {
00110 if (caps.dwClass == DMUS_PC_OUTPUTCLASS) {
00111
00112 DEBUG(driver, 1, " %d: %s%s", i, convert_from_fs(caps.wszDescription, desc, lengthof(desc)), i == port ? " (selected)" : "");
00113 }
00114 }
00115 }
00116 #endif
00117
00118 IDirectMusicPort *music_port = NULL;
00119
00120 if (port >= 0) {
00121
00122 DMUS_PORTCAPS caps;
00123 MemSetT(&caps, 0);
00124 caps.dwSize = sizeof(DMUS_PORTCAPS);
00125 if (FAILED(music->EnumPort(port, &caps))) return "Supplied port parameter is not a valid port";
00126 if (caps.dwClass != DMUS_PC_OUTPUTCLASS) return "Supplied port parameter is not an output port";
00127
00128
00129 DMUS_PORTPARAMS params;
00130 MemSetT(¶ms, 0);
00131 params.dwSize = sizeof(DMUS_PORTPARAMS);
00132 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
00133 params.dwChannelGroups = 1;
00134
00135 if (FAILED(music->CreatePort(caps.guidPort, ¶ms, &music_port, NULL))) {
00136 return "Failed to create port";
00137 }
00138
00139
00140 if (FAILED(music_port->Activate(TRUE))) {
00141 music_port->Release();
00142 return "Failed to activate port";
00143 }
00144 }
00145
00146
00147 if (FAILED(performance->AddPort(music_port))) {
00148 if (music_port != NULL) music_port->Release();
00149 return "AddPort failed";
00150 }
00151
00152
00153
00154 if (music_port != NULL) {
00155 if (FAILED(performance->AssignPChannelBlock(0, music_port, 1))) {
00156 music_port->Release();
00157 return "Failed to assign PChannel block";
00158 }
00159
00160 music_port->Release();
00161 }
00162
00163
00164 if (FAILED(proc.CoCreateInstance(
00165 CLSID_DirectMusicLoader,
00166 NULL,
00167 CLSCTX_INPROC,
00168 IID_IDirectMusicLoader,
00169 (LPVOID*)&loader
00170 ))) {
00171 return "Failed to create loader object";
00172 }
00173
00174 return NULL;
00175 }
00176
00177
00178 MusicDriver_DMusic::~MusicDriver_DMusic()
00179 {
00180 this->Stop();
00181 }
00182
00183
00184 void MusicDriver_DMusic::Stop()
00185 {
00186 seeking = false;
00187
00188 if (performance != NULL) performance->Stop(NULL, NULL, 0, 0);
00189
00190 if (segment != NULL) {
00191 segment->SetParam(GUID_Unload, 0xFFFFFFFF, 0, 0, performance);
00192 segment->Release();
00193 segment = NULL;
00194 }
00195
00196 if (music != NULL) {
00197 music->Release();
00198 music = NULL;
00199 }
00200
00201 if (performance != NULL) {
00202 performance->CloseDown();
00203 performance->Release();
00204 performance = NULL;
00205 }
00206
00207 if (loader != NULL) {
00208 loader->Release();
00209 loader = NULL;
00210 }
00211
00212 proc.CoUninitialize();
00213 }
00214
00215
00216 void MusicDriver_DMusic::PlaySong(const char *filename)
00217 {
00218
00219 DMUS_OBJECTDESC obj_desc;
00220 ZeroMemory(&obj_desc, sizeof(obj_desc));
00221 obj_desc.dwSize = sizeof(obj_desc);
00222 obj_desc.guidClass = CLSID_DirectMusicSegment;
00223 obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
00224 MultiByteToWideChar(
00225 CP_ACP, MB_PRECOMPOSED,
00226 filename, -1,
00227 obj_desc.wszFileName, lengthof(obj_desc.wszFileName)
00228 );
00229
00230
00231 if (segment != NULL) {
00232 segment->Release();
00233 segment = NULL;
00234 }
00235
00236
00237 if (FAILED(loader->GetObject(
00238 &obj_desc, IID_IDirectMusicSegment, (LPVOID*)&segment
00239 ))) {
00240 DEBUG(driver, 0, "DirectMusic: GetObject failed");
00241 return;
00242 }
00243
00244
00245 if (FAILED(segment->SetParam(
00246 GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, performance
00247 ))) {
00248 DEBUG(driver, 0, "DirectMusic: SetParam (MIDI file) failed");
00249 return;
00250 }
00251
00252
00253 if (FAILED(segment->SetParam(GUID_Download, 0xFFFFFFFF, 0, 0, performance))) {
00254 DEBUG(driver, 0, "DirectMusic: failed to download instruments");
00255 return;
00256 }
00257
00258
00259 if (FAILED(performance->PlaySegment(segment, 0, 0, NULL))) {
00260 DEBUG(driver, 0, "DirectMusic: PlaySegment failed");
00261 return;
00262 }
00263
00264 seeking = true;
00265 }
00266
00267
00268 void MusicDriver_DMusic::StopSong()
00269 {
00270 if (FAILED(performance->Stop(segment, NULL, 0, 0))) {
00271 DEBUG(driver, 0, "DirectMusic: StopSegment failed");
00272 }
00273 seeking = false;
00274 }
00275
00276
00277 bool MusicDriver_DMusic::IsSongPlaying()
00278 {
00279
00280
00281 if (performance->IsPlaying(segment, NULL) == S_OK) {
00282 seeking = false;
00283 return true;
00284 } else {
00285 return seeking;
00286 }
00287 }
00288
00289
00290 void MusicDriver_DMusic::SetVolume(byte vol)
00291 {
00292 long db = vol * 2000 / 127 - 2000;
00293 performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db));
00294 }
00295
00296
00297 #endif