diff options
Diffstat (limited to 'music/qtmidi.c')
-rw-r--r-- | music/qtmidi.c | 371 |
1 files changed, 0 insertions, 371 deletions
diff --git a/music/qtmidi.c b/music/qtmidi.c deleted file mode 100644 index 6f0a215d0..000000000 --- a/music/qtmidi.c +++ /dev/null @@ -1,371 +0,0 @@ -/* $Id$ */ - -/** - * @file qtmidi.c - * @brief MIDI music player for MacOS X using QuickTime. - * - * This music player should work in all MacOS X releases starting from 10.0, - * as QuickTime is an integral part of the system since the old days of the - * Motorola 68k-based Macintoshes. The only extra dependency apart from - * QuickTime itself is Carbon, which is included since 10.0 as well. - * - * QuickTime gets fooled with the MIDI files from Transport Tycoon Deluxe - * because of the @c .gm suffix. To force QuickTime to load the MIDI files - * without the need of dealing with the individual QuickTime components - * needed to play music (data source, MIDI parser, note allocators, - * synthesizers and the like) some Carbon functions are used to set the file - * type as seen by QuickTime, using @c FSpSetFInfo() (which modifies the - * file's resource fork). - */ - - -/* - * OpenTTD includes. - */ -#define WindowClass OSX_WindowClass -#include <QuickTime/QuickTime.h> -#undef WindowClass - -#include "../stdafx.h" -#include "../openttd.h" -#include "qtmidi.h" - -/* - * System includes. We need to workaround with some defines because there's - * stuff already defined in QuickTime headers. - */ -#define OTTD_Random OSX_OTTD_Random -#undef OTTD_Random -#undef WindowClass -#undef SL_ERROR -#undef bool - -#include <assert.h> -#include <unistd.h> -#include <fcntl.h> - -// we need to include debug.h after CoreServices because defining DEBUG will break CoreServices in OSX 10.2 -#include "../debug.h" - - -enum { - midiType = 'Midi' /**< OSType code for MIDI songs. */ -}; - - -/** - * Converts a Unix-like pathname to a @c FSSpec structure which may be - * used with functions from several MacOS X frameworks (Carbon, QuickTime, - * etc). The pointed file or directory must exist. - * - * @param *path A string containing a Unix-like path. - * @param *spec Pointer to a @c FSSpec structure where the result will be - * stored. - * @return Wether the conversion was successful. - */ -static bool PathToFSSpec(const char *path, FSSpec *spec) -{ - FSRef ref; - assert(spec != NULL); - assert(path != NULL); - - return - FSPathMakeRef((UInt8*)path, &ref, NULL) == noErr && - FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL) == noErr; -} - - -/** - * Sets the @c OSType of a given file to @c 'Midi', but only if it's not - * already set. - * - * @param *spec A @c FSSpec structure referencing a file. - */ -static void SetMIDITypeIfNeeded(const FSSpec *spec) -{ - FSRef ref; - FSCatalogInfo catalogInfo; - - assert(spec); - - if (noErr != FSpMakeFSRef(spec, &ref)) return; - if (noErr != FSGetCatalogInfo(&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return; - if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) { - FileInfo * const info = (FileInfo *) catalogInfo.finderInfo; - if (info->fileType != midiType && !(info->finderFlags & kIsAlias)) { - OSErr e; - info->fileType = midiType; - e = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo); - if (e == noErr) { - DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'"); - } else { - DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e); - } - } - } -} - - -/** - * Loads a MIDI file and returns it as a QuickTime Movie structure. - * - * @param *path String with the path of an existing MIDI file. - * @param *moov Pointer to a @c Movie where the result will be stored. - * @return Wether the file was loaded and the @c Movie successfully created. - */ -static bool LoadMovieForMIDIFile(const char *path, Movie *moov) -{ - int fd; - int ret; - char magic[4]; - FSSpec fsspec; - short refnum = 0; - short resid = 0; - - assert(path != NULL); - assert(moov != NULL); - - DEBUG(driver, 2, "qtmidi: start loading '%s'...", path); - - /* - * XXX Manual check for MIDI header ('MThd'), as I don't know how to make - * QuickTime load MIDI files without a .mid suffix without knowing it's - * a MIDI file and setting the OSType of the file to the 'Midi' value. - * Perhahaps ugly, but it seems that it does the Right Thing(tm). - */ - fd = open(path, O_RDONLY, 0); - if (fd == -1) return false; - ret = read(fd, magic, 4); - close(fd); - if (ret < 4) return false; - - DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic); - if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd') - return false; - - if (!PathToFSSpec(path, &fsspec)) return false; - SetMIDITypeIfNeeded(&fsspec); - - if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false; - DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path); - - if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL, - newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) { - CloseMovieFile(refnum); - return false; - } - DEBUG(driver, 3, "qtmidi: movie container created"); - - CloseMovieFile(refnum); - return true; -} - - -/** - * Flag which has the @c true value when QuickTime is available and - * initialized. - */ -static bool _quicktime_started = false; - - -/** - * Initialize QuickTime if needed. This function sets the - * #_quicktime_started flag to @c true if QuickTime is present in the system - * and it was initialized properly. - */ -static void InitQuickTimeIfNeeded(void) -{ - OSStatus dummy; - - if (_quicktime_started) return; - - DEBUG(driver, 2, "qtmidi: initializing Quicktime"); - /* Be polite: check wether QuickTime is available and initialize it. */ - _quicktime_started = - (noErr == Gestalt(gestaltQuickTime, &dummy)) && - (noErr == EnterMovies()); - if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!"); -} - - -/** Possible states of the QuickTime music driver. */ -enum { - QT_STATE_IDLE, /**< No file loaded. */ - QT_STATE_PLAY, /**< File loaded, playing. */ - QT_STATE_STOP, /**< File loaded, stopped. */ -}; - - -static Movie _quicktime_movie; /**< Current QuickTime @c Movie. */ -static byte _quicktime_volume = 127; /**< Current volume. */ -static int _quicktime_state = QT_STATE_IDLE; /**< Current player state. */ - - -/** - * Maps OpenTTD volume to QuickTime notion of volume. - */ -#define VOLUME ((short)((0x00FF & _quicktime_volume) << 1)) - - -static void StopSong(void); - - -/** - * Initialized the MIDI player, including QuickTime initialization. - * - * @todo Give better error messages by inspecting error codes returned by - * @c Gestalt() and @c EnterMovies(). Needs changes in - * #InitQuickTimeIfNeeded. - */ -static const char* StartDriver(const char * const *parm) -{ - InitQuickTimeIfNeeded(); - return (_quicktime_started) ? NULL : "can't initialize QuickTime"; -} - - -/** - * Checks wether the player is active. - * - * This function is called at regular intervals from OpenTTD's main loop, so - * we call @c MoviesTask() from here to let QuickTime do its work. - */ -static bool SongIsPlaying(void) -{ - if (!_quicktime_started) return true; - - switch (_quicktime_state) { - case QT_STATE_IDLE: - case QT_STATE_STOP: - /* Do nothing. */ - break; - case QT_STATE_PLAY: - MoviesTask(_quicktime_movie, 0); - /* Check wether movie ended. */ - if (IsMovieDone(_quicktime_movie) || - (GetMovieTime(_quicktime_movie, NULL) >= - GetMovieDuration(_quicktime_movie))) - _quicktime_state = QT_STATE_STOP; - } - - return _quicktime_state == QT_STATE_PLAY; -} - - -/** - * Stops the MIDI player. - * - * Stops playing and frees any used resources before returning. As it - * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false. - */ -static void StopDriver(void) -{ - if (!_quicktime_started) return; - - DEBUG(driver, 2, "qtmidi: stopping driver..."); - switch (_quicktime_state) { - case QT_STATE_IDLE: - DEBUG(driver, 3, "qtmidi: stopping not needed, already idle"); - /* Do nothing. */ - break; - case QT_STATE_PLAY: - StopSong(); - case QT_STATE_STOP: - DisposeMovie(_quicktime_movie); - } - - ExitMovies(); - _quicktime_started = false; -} - - -/** - * Starts playing a new song. - * - * @param filename Path to a MIDI file. - */ -static void PlaySong(const char *filename) -{ - if (!_quicktime_started) return; - - DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename); - switch (_quicktime_state) { - case QT_STATE_PLAY: - StopSong(); - DEBUG(driver, 3, "qtmidi: previous tune stopped"); - /* XXX Fall-through -- no break needed. */ - case QT_STATE_STOP: - DisposeMovie(_quicktime_movie); - DEBUG(driver, 3, "qtmidi: previous tune disposed"); - _quicktime_state = QT_STATE_IDLE; - /* XXX Fall-through -- no break needed. */ - case QT_STATE_IDLE: - LoadMovieForMIDIFile(filename, &_quicktime_movie); - SetMovieVolume(_quicktime_movie, VOLUME); - StartMovie(_quicktime_movie); - _quicktime_state = QT_STATE_PLAY; - } - DEBUG(driver, 3, "qtmidi: playing '%s'", filename); -} - - -/** - * Stops playing the current song, if the player is active. - */ -static void StopSong(void) -{ - if (!_quicktime_started) return; - - switch (_quicktime_state) { - case QT_STATE_IDLE: - /* XXX Fall-through -- no break needed. */ - case QT_STATE_STOP: - DEBUG(driver, 3, "qtmidi: stop requested, but already idle"); - /* Do nothing. */ - break; - case QT_STATE_PLAY: - StopMovie(_quicktime_movie); - _quicktime_state = QT_STATE_STOP; - DEBUG(driver, 3, "qtmidi: player stopped"); - } -} - - -/** - * Changes the playing volume of the MIDI player. - * - * As QuickTime controls volume in a per-movie basis, the desired volume is - * stored in #_quicktime_volume, and the volume is set here using the - * #VOLUME macro, @b and when loading new song in #PlaySong. - * - * @param vol The desired volume, range of the value is @c 0-127 - */ -static void SetVolume(byte vol) -{ - if (!_quicktime_started) return; - - _quicktime_volume = vol; - - DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME); - switch (_quicktime_state) { - case QT_STATE_IDLE: - /* Do nothing. */ - break; - case QT_STATE_PLAY: - case QT_STATE_STOP: - SetMovieVolume(_quicktime_movie, VOLUME); - } -} - - -/** - * Table of callbacks that implement the QuickTime MIDI player. - */ -const HalMusicDriver _qtime_music_driver = { - StartDriver, - StopDriver, - PlaySong, - StopSong, - SongIsPlaying, - SetVolume, -}; |