qtmidi.cpp

Go to the documentation of this file.
00001 /* $Id: qtmidi.cpp 17570 2009-09-19 09:51:14Z 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 
00029 #ifndef NO_QUICKTIME
00030 
00031 #include "../stdafx.h"
00032 #include "qtmidi.h"
00033 #include "../debug.h"
00034 
00035 #define Rect  OTTDRect
00036 #define Point OTTDPoint
00037 #include <QuickTime/QuickTime.h>
00038 #undef Rect
00039 #undef Point
00040 
00041 static FMusicDriver_QtMidi iFMusicDriver_QtMidi;
00042 
00043 
00044 enum {
00045   midiType = 'Midi' 
00046 };
00047 
00048 
00055 static void SetMIDITypeIfNeeded(const FSRef *ref)
00056 {
00057   FSCatalogInfo catalogInfo;
00058 
00059   assert(ref);
00060 
00061   if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return;
00062   if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
00063     FileInfo * const info = (FileInfo *) catalogInfo.finderInfo;
00064     if (info->fileType != midiType && !(info->finderFlags & kIsAlias)) {
00065       OSErr e;
00066       info->fileType = midiType;
00067       e = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
00068       if (e == noErr) {
00069         DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'");
00070       } else {
00071         DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e);
00072       }
00073     }
00074   }
00075 }
00076 
00077 
00085 static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
00086 {
00087   int fd;
00088   int ret;
00089   char magic[4];
00090   FSRef fsref;
00091   FSSpec fsspec;
00092   short refnum = 0;
00093   short resid  = 0;
00094 
00095   assert(path != NULL);
00096   assert(moov != NULL);
00097 
00098   DEBUG(driver, 2, "qtmidi: start loading '%s'...", path);
00099 
00100   /*
00101    * XXX Manual check for MIDI header ('MThd'), as I don't know how to make
00102    * QuickTime load MIDI files without a .mid suffix without knowing it's
00103    * a MIDI file and setting the OSType of the file to the 'Midi' value.
00104    * Perhahaps ugly, but it seems that it does the Right Thing(tm).
00105    */
00106   fd = open(path, O_RDONLY, 0);
00107   if (fd == -1) return false;
00108   ret = read(fd, magic, 4);
00109   close(fd);
00110   if (ret < 4) return false;
00111 
00112   DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic);
00113   if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd') {
00114     return false;
00115   }
00116 
00117   if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, NULL)) return false;
00118   SetMIDITypeIfNeeded(&fsref);
00119 
00120   if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL)) return false;
00121   if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
00122   DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path);
00123 
00124   if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
00125         newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) {
00126     CloseMovieFile(refnum);
00127     return false;
00128   }
00129   DEBUG(driver, 3, "qtmidi: movie container created");
00130 
00131   CloseMovieFile(refnum);
00132   return true;
00133 }
00134 
00135 
00140 static bool _quicktime_started = false;
00141 
00142 
00148 static void InitQuickTimeIfNeeded()
00149 {
00150   OSStatus dummy;
00151 
00152   if (_quicktime_started) return;
00153 
00154   DEBUG(driver, 2, "qtmidi: initializing Quicktime");
00155   /* Be polite: check wether QuickTime is available and initialize it. */
00156   _quicktime_started =
00157     (noErr == Gestalt(gestaltQuickTime, &dummy)) &&
00158     (noErr == EnterMovies());
00159   if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!");
00160 }
00161 
00162 
00164 enum {
00165   QT_STATE_IDLE, 
00166   QT_STATE_PLAY, 
00167   QT_STATE_STOP, 
00168 };
00169 
00170 
00171 static Movie _quicktime_movie;                  
00172 static byte  _quicktime_volume = 127;           
00173 static int   _quicktime_state  = QT_STATE_IDLE; 
00174 
00175 
00179 #define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
00180 
00181 
00189 const char *MusicDriver_QtMidi::Start(const char * const *parm)
00190 {
00191   InitQuickTimeIfNeeded();
00192   return (_quicktime_started) ? NULL : "can't initialize QuickTime";
00193 }
00194 
00195 
00202 bool MusicDriver_QtMidi::IsSongPlaying()
00203 {
00204   if (!_quicktime_started) return true;
00205 
00206   switch (_quicktime_state) {
00207     case QT_STATE_IDLE:
00208     case QT_STATE_STOP:
00209       /* Do nothing. */
00210       break;
00211 
00212     case QT_STATE_PLAY:
00213       MoviesTask(_quicktime_movie, 0);
00214       /* Check wether movie ended. */
00215       if (IsMovieDone(_quicktime_movie) ||
00216           (GetMovieTime(_quicktime_movie, NULL) >=
00217            GetMovieDuration(_quicktime_movie))) {
00218         _quicktime_state = QT_STATE_STOP;
00219       }
00220   }
00221 
00222   return _quicktime_state == QT_STATE_PLAY;
00223 }
00224 
00225 
00232 void MusicDriver_QtMidi::Stop()
00233 {
00234   if (!_quicktime_started) return;
00235 
00236   DEBUG(driver, 2, "qtmidi: stopping driver...");
00237   switch (_quicktime_state) {
00238     case QT_STATE_IDLE:
00239       DEBUG(driver, 3, "qtmidi: stopping not needed, already idle");
00240       /* Do nothing. */
00241       break;
00242 
00243     case QT_STATE_PLAY:
00244       StopSong();
00245       /* Fall-through */
00246 
00247     case QT_STATE_STOP:
00248       DisposeMovie(_quicktime_movie);
00249   }
00250 
00251   ExitMovies();
00252   _quicktime_started = false;
00253 }
00254 
00255 
00261 void MusicDriver_QtMidi::PlaySong(const char *filename)
00262 {
00263   if (!_quicktime_started) return;
00264 
00265   DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename);
00266   switch (_quicktime_state) {
00267     case QT_STATE_PLAY:
00268       StopSong();
00269       DEBUG(driver, 3, "qtmidi: previous tune stopped");
00270       /* Fall-through -- no break needed. */
00271 
00272     case QT_STATE_STOP:
00273       DisposeMovie(_quicktime_movie);
00274       DEBUG(driver, 3, "qtmidi: previous tune disposed");
00275       _quicktime_state = QT_STATE_IDLE;
00276       /* Fall-through -- no break needed. */
00277 
00278     case QT_STATE_IDLE:
00279       LoadMovieForMIDIFile(filename, &_quicktime_movie);
00280       SetMovieVolume(_quicktime_movie, VOLUME);
00281       StartMovie(_quicktime_movie);
00282       _quicktime_state = QT_STATE_PLAY;
00283   }
00284   DEBUG(driver, 3, "qtmidi: playing '%s'", filename);
00285 }
00286 
00287 
00291 void MusicDriver_QtMidi::StopSong()
00292 {
00293   if (!_quicktime_started) return;
00294 
00295   switch (_quicktime_state) {
00296     case QT_STATE_IDLE:
00297       /* Fall-through -- no break needed. */
00298 
00299     case QT_STATE_STOP:
00300       DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
00301       /* Do nothing. */
00302       break;
00303 
00304     case QT_STATE_PLAY:
00305       StopMovie(_quicktime_movie);
00306       _quicktime_state = QT_STATE_STOP;
00307       DEBUG(driver, 3, "qtmidi: player stopped");
00308   }
00309 }
00310 
00311 
00321 void MusicDriver_QtMidi::SetVolume(byte vol)
00322 {
00323   if (!_quicktime_started) return;
00324 
00325   _quicktime_volume = vol;
00326 
00327   DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME);
00328   switch (_quicktime_state) {
00329     case QT_STATE_IDLE:
00330       /* Do nothing. */
00331       break;
00332 
00333     case QT_STATE_PLAY:
00334     case QT_STATE_STOP:
00335       SetMovieVolume(_quicktime_movie, VOLUME);
00336   }
00337 }
00338 
00339 #endif /* NO_QUICKTIME */

Generated on Sat Jun 5 21:52:05 2010 for OpenTTD by  doxygen 1.6.1