qtmidi.cpp

Go to the documentation of this file.
00001 /* $Id: qtmidi.cpp 15718 2009-03-15 00:32:18Z rubidium $ */
00002 
00022 #define MAC_OS_X_VERSION_MIN_REQUIRED    MAC_OS_X_VERSION_10_3
00023 #include <AvailabilityMacros.h>
00024 
00025 /*
00026  * OpenTTD includes.
00027  */
00028 #define  WindowClass OSX_WindowClass
00029 #include <QuickTime/QuickTime.h>
00030 #undef   WindowClass
00031 
00032 #include "../stdafx.h"
00033 #include "qtmidi.h"
00034 
00035 /*
00036  * System includes. We need to workaround with some defines because there's
00037  * stuff already defined in QuickTime headers.
00038  */
00039 #define  OTTD_Random OSX_OTTD_Random
00040 #undef   OTTD_Random
00041 #undef   WindowClass
00042 #undef   SL_ERROR
00043 #undef   bool
00044 
00045 #include <assert.h>
00046 #include <unistd.h>
00047 #include <fcntl.h>
00048 
00049 /* we need to include debug.h after CoreServices because defining DEBUG will break CoreServices in OSX 10.2 */
00050 #include "../debug.h"
00051 
00052 static FMusicDriver_QtMidi iFMusicDriver_QtMidi;
00053 
00054 
00055 enum {
00056   midiType = 'Midi' 
00057 };
00058 
00059 
00066 static void SetMIDITypeIfNeeded(const FSRef *ref)
00067 {
00068   FSCatalogInfo catalogInfo;
00069 
00070   assert(ref);
00071 
00072   if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return;
00073   if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
00074     FileInfo * const info = (FileInfo *) catalogInfo.finderInfo;
00075     if (info->fileType != midiType && !(info->finderFlags & kIsAlias)) {
00076       OSErr e;
00077       info->fileType = midiType;
00078       e = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
00079       if (e == noErr) {
00080         DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'");
00081       } else {
00082         DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e);
00083       }
00084     }
00085   }
00086 }
00087 
00088 
00096 static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
00097 {
00098   int fd;
00099   int ret;
00100   char magic[4];
00101   FSRef fsref;
00102   FSSpec fsspec;
00103   short refnum = 0;
00104   short resid  = 0;
00105 
00106   assert(path != NULL);
00107   assert(moov != NULL);
00108 
00109   DEBUG(driver, 2, "qtmidi: start loading '%s'...", path);
00110 
00111   /*
00112    * XXX Manual check for MIDI header ('MThd'), as I don't know how to make
00113    * QuickTime load MIDI files without a .mid suffix without knowing it's
00114    * a MIDI file and setting the OSType of the file to the 'Midi' value.
00115    * Perhahaps ugly, but it seems that it does the Right Thing(tm).
00116    */
00117   fd = open(path, O_RDONLY, 0);
00118   if (fd == -1) return false;
00119   ret = read(fd, magic, 4);
00120   close(fd);
00121   if (ret < 4) return false;
00122 
00123   DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic);
00124   if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd')
00125     return false;
00126 
00127   if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, NULL)) return false;
00128   SetMIDITypeIfNeeded(&fsref);
00129 
00130   if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL)) return false;
00131   if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
00132   DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path);
00133 
00134   if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
00135         newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) {
00136     CloseMovieFile(refnum);
00137     return false;
00138   }
00139   DEBUG(driver, 3, "qtmidi: movie container created");
00140 
00141   CloseMovieFile(refnum);
00142   return true;
00143 }
00144 
00145 
00150 static bool _quicktime_started = false;
00151 
00152 
00158 static void InitQuickTimeIfNeeded()
00159 {
00160   OSStatus dummy;
00161 
00162   if (_quicktime_started) return;
00163 
00164   DEBUG(driver, 2, "qtmidi: initializing Quicktime");
00165   /* Be polite: check wether QuickTime is available and initialize it. */
00166   _quicktime_started =
00167     (noErr == Gestalt(gestaltQuickTime, &dummy)) &&
00168     (noErr == EnterMovies());
00169   if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!");
00170 }
00171 
00172 
00174 enum {
00175   QT_STATE_IDLE, 
00176   QT_STATE_PLAY, 
00177   QT_STATE_STOP, 
00178 };
00179 
00180 
00181 static Movie _quicktime_movie;                  
00182 static byte  _quicktime_volume = 127;           
00183 static int   _quicktime_state  = QT_STATE_IDLE; 
00184 
00185 
00189 #define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
00190 
00191 
00199 const char *MusicDriver_QtMidi::Start(const char * const *parm)
00200 {
00201   InitQuickTimeIfNeeded();
00202   return (_quicktime_started) ? NULL : "can't initialize QuickTime";
00203 }
00204 
00205 
00212 bool MusicDriver_QtMidi::IsSongPlaying()
00213 {
00214   if (!_quicktime_started) return true;
00215 
00216   switch (_quicktime_state) {
00217     case QT_STATE_IDLE:
00218     case QT_STATE_STOP:
00219       /* Do nothing. */
00220       break;
00221     case QT_STATE_PLAY:
00222       MoviesTask(_quicktime_movie, 0);
00223       /* Check wether movie ended. */
00224       if (IsMovieDone(_quicktime_movie) ||
00225           (GetMovieTime(_quicktime_movie, NULL) >=
00226            GetMovieDuration(_quicktime_movie)))
00227         _quicktime_state = QT_STATE_STOP;
00228   }
00229 
00230   return _quicktime_state == QT_STATE_PLAY;
00231 }
00232 
00233 
00240 void MusicDriver_QtMidi::Stop()
00241 {
00242   if (!_quicktime_started) return;
00243 
00244   DEBUG(driver, 2, "qtmidi: stopping driver...");
00245   switch (_quicktime_state) {
00246     case QT_STATE_IDLE:
00247       DEBUG(driver, 3, "qtmidi: stopping not needed, already idle");
00248       /* Do nothing. */
00249       break;
00250     case QT_STATE_PLAY:
00251       StopSong();
00252     case QT_STATE_STOP:
00253       DisposeMovie(_quicktime_movie);
00254   }
00255 
00256   ExitMovies();
00257   _quicktime_started = false;
00258 }
00259 
00260 
00266 void MusicDriver_QtMidi::PlaySong(const char *filename)
00267 {
00268   if (!_quicktime_started) return;
00269 
00270   DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename);
00271   switch (_quicktime_state) {
00272     case QT_STATE_PLAY:
00273       StopSong();
00274       DEBUG(driver, 3, "qtmidi: previous tune stopped");
00275       /* XXX Fall-through -- no break needed. */
00276     case QT_STATE_STOP:
00277       DisposeMovie(_quicktime_movie);
00278       DEBUG(driver, 3, "qtmidi: previous tune disposed");
00279       _quicktime_state = QT_STATE_IDLE;
00280       /* XXX Fall-through -- no break needed. */
00281     case QT_STATE_IDLE:
00282       LoadMovieForMIDIFile(filename, &_quicktime_movie);
00283       SetMovieVolume(_quicktime_movie, VOLUME);
00284       StartMovie(_quicktime_movie);
00285       _quicktime_state = QT_STATE_PLAY;
00286   }
00287   DEBUG(driver, 3, "qtmidi: playing '%s'", filename);
00288 }
00289 
00290 
00294 void MusicDriver_QtMidi::StopSong()
00295 {
00296   if (!_quicktime_started) return;
00297 
00298   switch (_quicktime_state) {
00299     case QT_STATE_IDLE:
00300       /* XXX Fall-through -- no break needed. */
00301     case QT_STATE_STOP:
00302       DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
00303       /* Do nothing. */
00304       break;
00305     case QT_STATE_PLAY:
00306       StopMovie(_quicktime_movie);
00307       _quicktime_state = QT_STATE_STOP;
00308       DEBUG(driver, 3, "qtmidi: player stopped");
00309   }
00310 }
00311 
00312 
00322 void MusicDriver_QtMidi::SetVolume(byte vol)
00323 {
00324   if (!_quicktime_started) return;
00325 
00326   _quicktime_volume = vol;
00327 
00328   DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME);
00329   switch (_quicktime_state) {
00330     case QT_STATE_IDLE:
00331       /* Do nothing. */
00332       break;
00333     case QT_STATE_PLAY:
00334     case QT_STATE_STOP:
00335       SetMovieVolume(_quicktime_movie, VOLUME);
00336   }
00337 }
00338 

Generated on Mon Jun 8 23:04:04 2009 for OpenTTD by  doxygen 1.5.6