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 static const uint MIDI_TYPE = 'Midi';
00045
00046
00053 static void SetMIDITypeIfNeeded(const FSRef *ref)
00054 {
00055 FSCatalogInfo catalogInfo;
00056
00057 assert(ref);
00058
00059 if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return;
00060 if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
00061 FileInfo * const info = (FileInfo *) catalogInfo.finderInfo;
00062 if (info->fileType != MIDI_TYPE && !(info->finderFlags & kIsAlias)) {
00063 OSErr e;
00064 info->fileType = MIDI_TYPE;
00065 e = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
00066 if (e == noErr) {
00067 DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'");
00068 } else {
00069 DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e);
00070 }
00071 }
00072 }
00073 }
00074
00075
00083 static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
00084 {
00085 int fd;
00086 int ret;
00087 char magic[4];
00088 FSRef fsref;
00089 FSSpec fsspec;
00090 short refnum = 0;
00091 short resid = 0;
00092
00093 assert(path != NULL);
00094 assert(moov != NULL);
00095
00096 DEBUG(driver, 2, "qtmidi: start loading '%s'...", path);
00097
00098
00099
00100
00101
00102
00103
00104 fd = open(path, O_RDONLY, 0);
00105 if (fd == -1) return false;
00106 ret = read(fd, magic, 4);
00107 close(fd);
00108 if (ret < 4) return false;
00109
00110 DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic);
00111 if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd') {
00112 return false;
00113 }
00114
00115 if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, NULL)) return false;
00116 SetMIDITypeIfNeeded(&fsref);
00117
00118 if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL)) return false;
00119 if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
00120 DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path);
00121
00122 if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
00123 newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) {
00124 CloseMovieFile(refnum);
00125 return false;
00126 }
00127 DEBUG(driver, 3, "qtmidi: movie container created");
00128
00129 CloseMovieFile(refnum);
00130 return true;
00131 }
00132
00133
00138 static bool _quicktime_started = false;
00139
00140
00146 static void InitQuickTimeIfNeeded()
00147 {
00148 OSStatus dummy;
00149
00150 if (_quicktime_started) return;
00151
00152 DEBUG(driver, 2, "qtmidi: initializing Quicktime");
00153
00154 _quicktime_started =
00155 (noErr == Gestalt(gestaltQuickTime, &dummy)) &&
00156 (noErr == EnterMovies());
00157 if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!");
00158 }
00159
00160
00162 enum QTStates {
00163 QT_STATE_IDLE,
00164 QT_STATE_PLAY,
00165 QT_STATE_STOP,
00166 };
00167
00168
00169 static Movie _quicktime_movie;
00170 static byte _quicktime_volume = 127;
00171 static int _quicktime_state = QT_STATE_IDLE;
00172
00173
00177 #define VOLUME ((short)((0x00FF & _quicktime_volume) << 1))
00178
00179
00187 const char *MusicDriver_QtMidi::Start(const char * const *parm)
00188 {
00189 InitQuickTimeIfNeeded();
00190 return (_quicktime_started) ? NULL : "can't initialize QuickTime";
00191 }
00192
00193
00200 bool MusicDriver_QtMidi::IsSongPlaying()
00201 {
00202 if (!_quicktime_started) return true;
00203
00204 switch (_quicktime_state) {
00205 case QT_STATE_IDLE:
00206 case QT_STATE_STOP:
00207
00208 break;
00209
00210 case QT_STATE_PLAY:
00211 MoviesTask(_quicktime_movie, 0);
00212
00213 if (IsMovieDone(_quicktime_movie) ||
00214 (GetMovieTime(_quicktime_movie, NULL) >=
00215 GetMovieDuration(_quicktime_movie))) {
00216 _quicktime_state = QT_STATE_STOP;
00217 }
00218 }
00219
00220 return _quicktime_state == QT_STATE_PLAY;
00221 }
00222
00223
00230 void MusicDriver_QtMidi::Stop()
00231 {
00232 if (!_quicktime_started) return;
00233
00234 DEBUG(driver, 2, "qtmidi: stopping driver...");
00235 switch (_quicktime_state) {
00236 case QT_STATE_IDLE:
00237 DEBUG(driver, 3, "qtmidi: stopping not needed, already idle");
00238
00239 break;
00240
00241 case QT_STATE_PLAY:
00242 StopSong();
00243
00244
00245 case QT_STATE_STOP:
00246 DisposeMovie(_quicktime_movie);
00247 }
00248
00249 ExitMovies();
00250 _quicktime_started = false;
00251 }
00252
00253
00259 void MusicDriver_QtMidi::PlaySong(const char *filename)
00260 {
00261 if (!_quicktime_started) return;
00262
00263 DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename);
00264 switch (_quicktime_state) {
00265 case QT_STATE_PLAY:
00266 StopSong();
00267 DEBUG(driver, 3, "qtmidi: previous tune stopped");
00268
00269
00270 case QT_STATE_STOP:
00271 DisposeMovie(_quicktime_movie);
00272 DEBUG(driver, 3, "qtmidi: previous tune disposed");
00273 _quicktime_state = QT_STATE_IDLE;
00274
00275
00276 case QT_STATE_IDLE:
00277 LoadMovieForMIDIFile(filename, &_quicktime_movie);
00278 SetMovieVolume(_quicktime_movie, VOLUME);
00279 StartMovie(_quicktime_movie);
00280 _quicktime_state = QT_STATE_PLAY;
00281 }
00282 DEBUG(driver, 3, "qtmidi: playing '%s'", filename);
00283 }
00284
00285
00289 void MusicDriver_QtMidi::StopSong()
00290 {
00291 if (!_quicktime_started) return;
00292
00293 switch (_quicktime_state) {
00294 case QT_STATE_IDLE:
00295
00296
00297 case QT_STATE_STOP:
00298 DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
00299
00300 break;
00301
00302 case QT_STATE_PLAY:
00303 StopMovie(_quicktime_movie);
00304 _quicktime_state = QT_STATE_STOP;
00305 DEBUG(driver, 3, "qtmidi: player stopped");
00306 }
00307 }
00308
00309
00319 void MusicDriver_QtMidi::SetVolume(byte vol)
00320 {
00321 if (!_quicktime_started) return;
00322
00323 _quicktime_volume = vol;
00324
00325 DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME);
00326 switch (_quicktime_state) {
00327 case QT_STATE_IDLE:
00328
00329 break;
00330
00331 case QT_STATE_PLAY:
00332 case QT_STATE_STOP:
00333 SetMovieVolume(_quicktime_movie, VOLUME);
00334 }
00335 }
00336
00337 #endif