win32_m.cpp

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

Generated on Wed Mar 17 23:50:12 2010 for OpenTTD by  doxygen 1.6.1