tron@2186: /* $Id$ */ tron@2186: tron@2189: #include "../stdafx.h" tron@2189: #include "../openttd.h" tron@2189: #include "win32_m.h" truelight@0: #include tron@2189: #include truelight@0: tron@1468: static struct { truelight@0: bool stop_song; truelight@0: bool terminate; truelight@0: bool playing; truelight@0: int new_vol; truelight@0: HANDLE wait_obj; tron@2458: UINT_PTR devid; truelight@0: char start_song[260]; truelight@0: } _midi; truelight@0: truelight@0: static void Win32MidiPlaySong(const char *filename) truelight@0: { truelight@0: strcpy(_midi.start_song, filename); truelight@0: _midi.playing = true; truelight@0: _midi.stop_song = false; truelight@0: SetEvent(_midi.wait_obj); truelight@0: } truelight@0: darkvater@1102: static void Win32MidiStopSong(void) truelight@0: { truelight@0: if (_midi.playing) { truelight@0: _midi.stop_song = true; tron@1468: _midi.start_song[0] = '\0'; truelight@0: SetEvent(_midi.wait_obj); truelight@0: } truelight@0: } truelight@0: darkvater@1102: static bool Win32MidiIsSongPlaying(void) truelight@0: { truelight@0: return _midi.playing; truelight@0: } truelight@0: truelight@0: static void Win32MidiSetVolume(byte vol) truelight@0: { truelight@0: _midi.new_vol = vol; truelight@0: SetEvent(_midi.wait_obj); truelight@0: } truelight@0: tron@2548: static MCIERROR CDECL MidiSendCommand(const char* cmd, ...) tron@2548: { truelight@0: va_list va; truelight@0: char buf[512]; tron@1468: truelight@0: va_start(va, cmd); truelight@0: vsprintf(buf, cmd, va); truelight@0: va_end(va); truelight@0: return mciSendStringA(buf, NULL, 0, 0); truelight@0: } truelight@0: truelight@0: static bool MidiIntPlaySong(const char *filename) truelight@0: { truelight@0: MidiSendCommand("close all"); tron@2054: if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0) truelight@0: return false; truelight@0: truelight@0: if (MidiSendCommand("play song from 0") != 0) truelight@0: return false; truelight@0: return true; truelight@0: } truelight@0: darkvater@1102: static void MidiIntStopSong(void) truelight@0: { truelight@0: MidiSendCommand("close all"); truelight@0: } truelight@0: truelight@0: static void MidiIntSetVolume(int vol) truelight@0: { tron@2458: DWORD v = (vol * 65535 / 127); Darkvater@2434: midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16)); truelight@0: } truelight@0: darkvater@1102: static bool MidiIntIsSongPlaying(void) truelight@0: { truelight@0: char buf[16]; truelight@0: mciSendStringA("status song mode", buf, sizeof(buf), 0); truelight@0: return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; truelight@0: } truelight@0: truelight@0: static DWORD WINAPI MidiThread(LPVOID arg) truelight@0: { truelight@0: _midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL); truelight@0: truelight@0: do { tron@1468: char *s; tron@1468: int vol; tron@1468: tron@1468: vol = _midi.new_vol; tron@1468: if (vol != -1) { truelight@0: _midi.new_vol = -1; truelight@0: MidiIntSetVolume(vol); truelight@0: } tron@1468: tron@1468: s = _midi.start_song; tron@1468: if (s[0] != '\0') { truelight@0: _midi.playing = MidiIntPlaySong(s); tron@1468: s[0] = '\0'; truelight@193: truelight@0: // Delay somewhat in case we don't manage to play. truelight@0: if (!_midi.playing) { truelight@193: Sleep(5000); truelight@0: } truelight@0: } tron@1468: tron@1468: if (_midi.stop_song && _midi.playing) { truelight@0: _midi.stop_song = false; truelight@0: _midi.playing = false; truelight@0: MidiIntStopSong(); truelight@0: } truelight@0: truelight@0: if (_midi.playing && !MidiIntIsSongPlaying()) truelight@0: _midi.playing = false; truelight@0: truelight@0: WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); truelight@0: } while (!_midi.terminate); truelight@0: truelight@0: DeleteObject(_midi.wait_obj); truelight@0: return 0; truelight@0: } truelight@0: tron@1301: static const char *Win32MidiStart(const char * const *parm) truelight@0: { Darkvater@2434: MIDIOUTCAPS midicaps; truelight@0: 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@1468: truelight@0: memset(&_midi, 0, sizeof(_midi)); truelight@0: _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; truelight@0: } truelight@0: darkvater@1102: static void Win32MidiStop(void) truelight@0: { truelight@0: _midi.terminate = true; truelight@0: SetEvent(_midi.wait_obj); truelight@0: } truelight@0: truelight@0: const HalMusicDriver _win32_music_driver = { truelight@0: Win32MidiStart, truelight@0: Win32MidiStop, truelight@0: Win32MidiPlaySong, truelight@0: Win32MidiStopSong, truelight@0: Win32MidiIsSongPlaying, truelight@0: Win32MidiSetVolume, truelight@0: };