OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

win32_m.cpp
Go to the documentation of this file.
1 /* $Id: win32_m.cpp 27673 2016-10-30 18:22:55Z michi_cc $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
9
12 #include "../stdafx.h"
13 #include "../string_func.h"
14 #include "win32_m.h"
15 #include <windows.h>
16 #include <mmsystem.h>
17 #include "../os/windows/win32.h"
18
19 #include "../safeguards.h"
20
21 static struct {
22 bool stop_song;
23 bool terminate;
24 bool playing;
25 int new_vol;
26 HANDLE wait_obj;
27 HANDLE thread;
28 UINT_PTR devid;
29 char start_song[MAX_PATH];
30 } _midi;
31
32 static FMusicDriver_Win32 iFMusicDriver_Win32;
33
34 void MusicDriver_Win32::PlaySong(const char *filename)
35 {
36 assert(filename != NULL);
37 strecpy(_midi.start_song, filename, lastof(_midi.start_song));
38 _midi.playing = true;
39 _midi.stop_song = false;
40 SetEvent(_midi.wait_obj);
41 }
42
43 void MusicDriver_Win32::StopSong()
44 {
45 if (_midi.playing) {
46 _midi.stop_song = true;
47 _midi.start_song[0] = '\0';
48 SetEvent(_midi.wait_obj);
49 }
50 }
51
52 bool MusicDriver_Win32::IsSongPlaying()
53 {
54 return _midi.playing;
55 }
56
57 void MusicDriver_Win32::SetVolume(byte vol)
58 {
59 _midi.new_vol = vol;
60 SetEvent(_midi.wait_obj);
61 }
62
63 static MCIERROR CDECL MidiSendCommand(const TCHAR *cmd, ...)
64 {
65 va_list va;
66 TCHAR buf[512];
67
68 va_start(va, cmd);
69 _vsntprintf(buf, lengthof(buf), cmd, va);
70 va_end(va);
71 return mciSendString(buf, NULL, 0, 0);
72 }
73
74 static bool MidiIntPlaySong(const char *filename)
75 {
76 MidiSendCommand(_T("close all"));
77
78 if (MidiSendCommand(_T("open \"%s\" type sequencer alias song"), OTTD2FS(filename)) != 0) {
79 /* Let's try the "short name" */
80 TCHAR buf[MAX_PATH];
81 if (GetShortPathName(OTTD2FS(filename), buf, MAX_PATH) == 0) return false;
82 if (MidiSendCommand(_T("open \"%s\" type sequencer alias song"), buf) != 0) return false;
83 }
84
85 MidiSendCommand(_T("seek song to start wait"));
86 return MidiSendCommand(_T("play song")) == 0;
87 }
88
89 static void MidiIntStopSong()
90 {
91 MidiSendCommand(_T("close all"));
92 }
93
94 static void MidiIntSetVolume(int vol)
95 {
96 DWORD v = (vol * 65535 / 127);
97 midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16));
98 }
99
100 static bool MidiIntIsSongPlaying()
101 {
102 char buf[16];
103 mciSendStringA("status song mode", buf, sizeof(buf), 0);
104 return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
105 }
106
107 static DWORD WINAPI MidiThread(LPVOID arg)
108 {
109 SetWin32ThreadName(-1, "ottd:win-midi");
110
111 do {
112 char *s;
113 int vol;
114
115 vol = _midi.new_vol;
116 if (vol != -1) {
117 _midi.new_vol = -1;
118 MidiIntSetVolume(vol);
119 }
120
121 s = _midi.start_song;
122 if (s[0] != '\0') {
123 _midi.playing = MidiIntPlaySong(s);
124 s[0] = '\0';
125
126 /* Delay somewhat in case we don't manage to play. */
127 if (!_midi.playing) WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 5000);
128 }
129
130 if (_midi.stop_song && _midi.playing) {
131 _midi.stop_song = false;
132 _midi.playing = false;
133 MidiIntStopSong();
134 }
135
136 if (_midi.playing && !MidiIntIsSongPlaying()) _midi.playing = false;
137
138 WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000);
139 } while (!_midi.terminate);
140
141 MidiIntStopSong();
142 return 0;
143 }
144
145 const char *MusicDriver_Win32::Start(const char * const *parm)
146 {
147 MIDIOUTCAPS midicaps;
148 UINT nbdev;
149 UINT_PTR dev;
150 char buf[16];
151
152 mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0);
153 if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio";
154
155 memset(&_midi, 0, sizeof(_midi));
156 _midi.new_vol = -1;
157
158 /* Get midi device */
159 _midi.devid = MIDI_MAPPER;
160 for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) {
161 if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) {
162 _midi.devid = dev;
163 break;
164 }
165 }
166
167 if (NULL == (_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL))) return "Failed to create event";
168
169 /* The lpThreadId parameter of CreateThread (the last parameter)
170 * may NOT be NULL on Windows 95, 98 and ME. */
171 DWORD threadId;
172 if (NULL == (_midi.thread = CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId))) return "Failed to create thread";
173
174 return NULL;
175 }
176
177 void MusicDriver_Win32::Stop()
178 {
179 _midi.terminate = true;
180 SetEvent(_midi.wait_obj);
181 WaitForMultipleObjects(1, &_midi.thread, true, INFINITE);
182 CloseHandle(_midi.wait_obj);
183 CloseHandle(_midi.thread);
184 }