tron@2186: /* $Id$ */ tron@2186: tron@2189: #include "../stdafx.h" tron@2189: #include "../openttd.h" tron@2189: #include "win32_m.h" tron@2174: #include tron@2189: #include tron@2174: tron@2174: static struct { tron@2174: bool stop_song; tron@2174: bool terminate; tron@2174: bool playing; tron@2174: int new_vol; tron@2174: HANDLE wait_obj; tron@2458: UINT_PTR devid; tron@2174: char start_song[260]; tron@2174: } _midi; tron@2174: tron@2174: static void Win32MidiPlaySong(const char *filename) tron@2174: { tron@2174: strcpy(_midi.start_song, filename); tron@2174: _midi.playing = true; tron@2174: _midi.stop_song = false; tron@2174: SetEvent(_midi.wait_obj); tron@2174: } tron@2174: tron@2174: static void Win32MidiStopSong(void) tron@2174: { tron@2174: if (_midi.playing) { tron@2174: _midi.stop_song = true; tron@2174: _midi.start_song[0] = '\0'; tron@2174: SetEvent(_midi.wait_obj); tron@2174: } tron@2174: } tron@2174: tron@2174: static bool Win32MidiIsSongPlaying(void) tron@2174: { tron@2174: return _midi.playing; tron@2174: } tron@2174: tron@2174: static void Win32MidiSetVolume(byte vol) tron@2174: { tron@2174: _midi.new_vol = vol; tron@2174: SetEvent(_midi.wait_obj); tron@2174: } tron@2174: tron@2548: static MCIERROR CDECL MidiSendCommand(const char* cmd, ...) tron@2548: { tron@2174: va_list va; tron@2174: char buf[512]; tron@2174: tron@2174: va_start(va, cmd); tron@2174: vsprintf(buf, cmd, va); tron@2174: va_end(va); tron@2174: return mciSendStringA(buf, NULL, 0, 0); tron@2174: } tron@2174: tron@2174: static bool MidiIntPlaySong(const char *filename) tron@2174: { tron@2174: MidiSendCommand("close all"); tron@2174: if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0) tron@2174: return false; tron@2174: tron@2174: if (MidiSendCommand("play song from 0") != 0) tron@2174: return false; tron@2174: return true; tron@2174: } tron@2174: tron@2174: static void MidiIntStopSong(void) tron@2174: { tron@2174: MidiSendCommand("close all"); tron@2174: } tron@2174: tron@2174: static void MidiIntSetVolume(int vol) tron@2174: { tron@2458: DWORD v = (vol * 65535 / 127); Darkvater@2434: midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16)); tron@2174: } tron@2174: tron@2174: static bool MidiIntIsSongPlaying(void) tron@2174: { tron@2174: char buf[16]; tron@2174: mciSendStringA("status song mode", buf, sizeof(buf), 0); tron@2174: return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; tron@2174: } tron@2174: tron@2174: static DWORD WINAPI MidiThread(LPVOID arg) tron@2174: { tron@2174: _midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL); tron@2174: tron@2174: do { tron@2174: char *s; tron@2174: int vol; tron@2174: tron@2174: vol = _midi.new_vol; tron@2174: if (vol != -1) { tron@2174: _midi.new_vol = -1; tron@2174: MidiIntSetVolume(vol); tron@2174: } tron@2174: tron@2174: s = _midi.start_song; tron@2174: if (s[0] != '\0') { tron@2174: _midi.playing = MidiIntPlaySong(s); tron@2174: s[0] = '\0'; tron@2174: tron@2174: // Delay somewhat in case we don't manage to play. tron@2174: if (!_midi.playing) { tron@2174: Sleep(5000); tron@2174: } tron@2174: } tron@2174: tron@2174: if (_midi.stop_song && _midi.playing) { tron@2174: _midi.stop_song = false; tron@2174: _midi.playing = false; tron@2174: MidiIntStopSong(); tron@2174: } tron@2174: tron@2174: if (_midi.playing && !MidiIntIsSongPlaying()) tron@2174: _midi.playing = false; tron@2174: tron@2174: WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); tron@2174: } while (!_midi.terminate); tron@2174: tron@2174: DeleteObject(_midi.wait_obj); tron@2174: return 0; tron@2174: } tron@2174: tron@2174: static const char *Win32MidiStart(const char * const *parm) tron@2174: { Darkvater@2434: MIDIOUTCAPS midicaps; tron@2174: DWORD threadId; tron@2458: UINT nbdev; tron@2458: UINT_PTR dev; tron@2212: char buf[16]; tron@2212: tron@2212: mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0); tron@2212: if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio"; tron@2174: tron@2174: memset(&_midi, 0, sizeof(_midi)); tron@2174: _midi.new_vol = -1; tron@2212: Darkvater@2434: /* Get midi device */ Darkvater@2434: _midi.devid = MIDI_MAPPER; Darkvater@2434: for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) { Darkvater@2434: if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) { Darkvater@2434: _midi.devid = dev; Darkvater@2434: break; Darkvater@2434: } Darkvater@2434: } Darkvater@2434: tron@2212: if (CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId) == NULL) tron@2212: return "Failed to create thread"; tron@2212: tron@2212: return NULL; tron@2174: } tron@2174: tron@2174: static void Win32MidiStop(void) tron@2174: { tron@2174: _midi.terminate = true; tron@2174: SetEvent(_midi.wait_obj); tron@2174: } tron@2174: tron@2174: const HalMusicDriver _win32_music_driver = { tron@2174: Win32MidiStart, tron@2174: Win32MidiStop, tron@2174: Win32MidiPlaySong, tron@2174: Win32MidiStopSong, tron@2174: Win32MidiIsSongPlaying, tron@2174: Win32MidiSetVolume, tron@2174: };