win32_m.cpp
00001
00002
00003 #include "../stdafx.h"
00004 #include "win32_m.h"
00005 #include <windows.h>
00006 #include <mmsystem.h>
00007
00008 static struct {
00009 bool stop_song;
00010 bool terminate;
00011 bool playing;
00012 int new_vol;
00013 HANDLE wait_obj;
00014 HANDLE thread;
00015 UINT_PTR devid;
00016 char start_song[MAX_PATH];
00017 } _midi;
00018
00019 static FMusicDriver_Win32 iFMusicDriver_Win32;
00020
00021 void MusicDriver_Win32::PlaySong(const char *filename)
00022 {
00023 assert(filename != NULL);
00024 strcpy(_midi.start_song, filename);
00025 _midi.playing = true;
00026 _midi.stop_song = false;
00027 SetEvent(_midi.wait_obj);
00028 }
00029
00030 void MusicDriver_Win32::StopSong()
00031 {
00032 if (_midi.playing) {
00033 _midi.stop_song = true;
00034 _midi.start_song[0] = '\0';
00035 SetEvent(_midi.wait_obj);
00036 }
00037 }
00038
00039 bool MusicDriver_Win32::IsSongPlaying()
00040 {
00041 return _midi.playing;
00042 }
00043
00044 void MusicDriver_Win32::SetVolume(byte vol)
00045 {
00046 _midi.new_vol = vol;
00047 SetEvent(_midi.wait_obj);
00048 }
00049
00050 static MCIERROR CDECL MidiSendCommand(const TCHAR* cmd, ...)
00051 {
00052 va_list va;
00053 TCHAR buf[512];
00054
00055 va_start(va, cmd);
00056 _vsntprintf(buf, lengthof(buf), cmd, va);
00057 va_end(va);
00058 return mciSendString(buf, NULL, 0, 0);
00059 }
00060
00061 static bool MidiIntPlaySong(const char *filename)
00062 {
00063 MidiSendCommand(_T("close all"));
00064
00065 if (MidiSendCommand(_T("open \"%s\" type sequencer alias song"), OTTD2FS(filename)) != 0) {
00066
00067 TCHAR buf[MAX_PATH];
00068 if (GetShortPathName(OTTD2FS(filename), buf, MAX_PATH) == 0) return false;
00069 if (MidiSendCommand(_T("open \"%s\" type sequencer alias song"), buf) != 0) return false;
00070 }
00071
00072 return MidiSendCommand(_T("play song from 0")) == 0;
00073 }
00074
00075 static void MidiIntStopSong()
00076 {
00077 MidiSendCommand(_T("close all"));
00078 }
00079
00080 static void MidiIntSetVolume(int vol)
00081 {
00082 DWORD v = (vol * 65535 / 127);
00083 midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16));
00084 }
00085
00086 static bool MidiIntIsSongPlaying()
00087 {
00088 char buf[16];
00089 mciSendStringA("status song mode", buf, sizeof(buf), 0);
00090 return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
00091 }
00092
00093 static DWORD WINAPI MidiThread(LPVOID arg)
00094 {
00095 do {
00096 char *s;
00097 int vol;
00098
00099 vol = _midi.new_vol;
00100 if (vol != -1) {
00101 _midi.new_vol = -1;
00102 MidiIntSetVolume(vol);
00103 }
00104
00105 s = _midi.start_song;
00106 if (s[0] != '\0') {
00107 _midi.playing = MidiIntPlaySong(s);
00108 s[0] = '\0';
00109
00110
00111 if (!_midi.playing) WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 5000);
00112 }
00113
00114 if (_midi.stop_song && _midi.playing) {
00115 _midi.stop_song = false;
00116 _midi.playing = false;
00117 MidiIntStopSong();
00118 }
00119
00120 if (_midi.playing && !MidiIntIsSongPlaying()) _midi.playing = false;
00121
00122 WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000);
00123 } while (!_midi.terminate);
00124
00125 MidiIntStopSong();
00126 return 0;
00127 }
00128
00129 const char *MusicDriver_Win32::Start(const char * const *parm)
00130 {
00131 MIDIOUTCAPS midicaps;
00132 UINT nbdev;
00133 UINT_PTR dev;
00134 char buf[16];
00135
00136 mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0);
00137 if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio";
00138
00139 memset(&_midi, 0, sizeof(_midi));
00140 _midi.new_vol = -1;
00141
00142
00143 _midi.devid = MIDI_MAPPER;
00144 for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) {
00145 if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) {
00146 _midi.devid = dev;
00147 break;
00148 }
00149 }
00150
00151 if (NULL == (_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL))) return "Failed to create event";
00152
00153
00154
00155 DWORD threadId;
00156 if (NULL == (_midi.thread = CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId))) return "Failed to create thread";
00157
00158 return NULL;
00159 }
00160
00161 void MusicDriver_Win32::Stop()
00162 {
00163 _midi.terminate = true;
00164 SetEvent(_midi.wait_obj);
00165 WaitForMultipleObjects(1, &_midi.thread, true, INFINITE);
00166 CloseHandle(_midi.wait_obj);
00167 CloseHandle(_midi.thread);
00168 }