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