00001
00002
00003
00004
00005
00006
00007
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
00102
00103
00104
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
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
00210 break;
00211
00212 case QT_STATE_PLAY:
00213 MoviesTask(_quicktime_movie, 0);
00214
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
00241 break;
00242
00243 case QT_STATE_PLAY:
00244 StopSong();
00245
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
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
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
00298
00299 case QT_STATE_STOP:
00300 DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
00301
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
00331 break;
00332
00333 case QT_STATE_PLAY:
00334 case QT_STATE_STOP:
00335 SetMovieVolume(_quicktime_movie, VOLUME);
00336 }
00337 }
00338
00339 #endif