win32_m.cpp

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

Generated on Mon Sep 22 20:34:16 2008 for openttd by  doxygen 1.5.6