win32_m.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
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     /* Let's try the "short name" */
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       /* Delay somewhat in case we don't manage to play. */
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   /* Get midi device */
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   /* The lpThreadId parameter of CreateThread (the last parameter)
00163    * may NOT be NULL on Windows 95, 98 and ME. */
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 }

Generated on Wed Dec 30 20:40:03 2009 for OpenTTD by  doxygen 1.5.6