00001
00002
00022 #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3
00023 #include <AvailabilityMacros.h>
00024
00025
00026
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
00037
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
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
00113
00114
00115
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
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
00220 break;
00221 case QT_STATE_PLAY:
00222 MoviesTask(_quicktime_movie, 0);
00223
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
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
00276 case QT_STATE_STOP:
00277 DisposeMovie(_quicktime_movie);
00278 DEBUG(driver, 3, "qtmidi: previous tune disposed");
00279 _quicktime_state = QT_STATE_IDLE;
00280
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
00301 case QT_STATE_STOP:
00302 DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
00303
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
00332 break;
00333 case QT_STATE_PLAY:
00334 case QT_STATE_STOP:
00335 SetMovieVolume(_quicktime_movie, VOLUME);
00336 }
00337 }
00338