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