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 return MidiSendCommand(_T("play song from 0")) == 0;
00083 }
00084
00085 static void MidiIntStopSong()
00086 {
00087 MidiSendCommand(_T("close all"));
00088 }
00089
00090 static void MidiIntSetVolume(int vol)
00091 {
00092 DWORD v = (vol * 65535 / 127);
00093 midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16));
00094 }
00095
00096 static bool MidiIntIsSongPlaying()
00097 {
00098 char buf[16];
00099 mciSendStringA("status song mode", buf, sizeof(buf), 0);
00100 return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
00101 }
00102
00103 static DWORD WINAPI MidiThread(LPVOID arg)
00104 {
00105 do {
00106 char *s;
00107 int vol;
00108
00109 vol = _midi.new_vol;
00110 if (vol != -1) {
00111 _midi.new_vol = -1;
00112 MidiIntSetVolume(vol);
00113 }
00114
00115 s = _midi.start_song;
00116 if (s[0] != '\0') {
00117 _midi.playing = MidiIntPlaySong(s);
00118 s[0] = '\0';
00119
00120
00121 if (!_midi.playing) WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 5000);
00122 }
00123
00124 if (_midi.stop_song && _midi.playing) {
00125 _midi.stop_song = false;
00126 _midi.playing = false;
00127 MidiIntStopSong();
00128 }
00129
00130 if (_midi.playing && !MidiIntIsSongPlaying()) _midi.playing = false;
00131
00132 WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000);
00133 } while (!_midi.terminate);
00134
00135 MidiIntStopSong();
00136 return 0;
00137 }
00138
00139 const char *MusicDriver_Win32::Start(const char * const *parm)
00140 {
00141 MIDIOUTCAPS midicaps;
00142 UINT nbdev;
00143 UINT_PTR dev;
00144 char buf[16];
00145
00146 mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0);
00147 if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio";
00148
00149 memset(&_midi, 0, sizeof(_midi));
00150 _midi.new_vol = -1;
00151
00152
00153 _midi.devid = MIDI_MAPPER;
00154 for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) {
00155 if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) {
00156 _midi.devid = dev;
00157 break;
00158 }
00159 }
00160
00161 if (NULL == (_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL))) return "Failed to create event";
00162
00163
00164
00165 DWORD threadId;
00166 if (NULL == (_midi.thread = CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId))) return "Failed to create thread";
00167
00168 return NULL;
00169 }
00170
00171 void MusicDriver_Win32::Stop()
00172 {
00173 _midi.terminate = true;
00174 SetEvent(_midi.wait_obj);
00175 WaitForMultipleObjects(1, &_midi.thread, true, INFINITE);
00176 CloseHandle(_midi.wait_obj);
00177 CloseHandle(_midi.thread);
00178 }