win32_m.cpp

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

Generated on Mon May 11 15:48:04 2009 for OpenTTD by  doxygen 1.5.6