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