1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-23 14:39:08 +00:00

(svn r7759) -Merge: makefile rewrite. This merge features:

- A proper ./configure, so everything needs to be configured only once, not for every make.
 - Usage of makedepend when available. This greatly reduces the time needed for generating the dependencies.
 - A generator for all project files. There is a single file with sources, which is used to generate Makefiles and the project files for MSVC.
 - Proper support for OSX universal binaries.
 - Object files for non-MSVC compiles are also placed in separate directories, making is faster to switch between debug and release compiles and it does not touch the directory with the source files.
 - Functionality to make a bundle of all needed files for for example a nightly or distribution of a binary with all needed GRFs and language files.

Note: as this merge moves almost all files, it is recommended to make a backup of your working copy before updating your working copy.
This commit is contained in:
rubidium
2007-01-02 19:19:48 +00:00
parent ccc0a3f4db
commit 66bbf336c6
448 changed files with 8150 additions and 6127 deletions

53
src/music/bemidi.cpp Normal file
View File

@@ -0,0 +1,53 @@
/* $Id$ */
#include "../stdafx.h"
#include "../openttd.h"
#include "bemidi.h"
// BeOS System Includes
#include <MidiSynthFile.h>
static BMidiSynthFile midiSynthFile;
static const char *bemidi_start(const char * const *parm)
{
return NULL;
}
static void bemidi_stop(void)
{
midiSynthFile.UnloadFile();
}
static void bemidi_play_song(const char *filename)
{
bemidi_stop();
entry_ref midiRef;
get_ref_for_path(filename, &midiRef);
midiSynthFile.LoadFile(&midiRef);
midiSynthFile.Start();
}
static void bemidi_stop_song(void)
{
midiSynthFile.UnloadFile();
}
static bool bemidi_is_playing(void)
{
return !midiSynthFile.IsFinished();
}
static void bemidi_set_volume(byte vol)
{
fprintf(stderr, "BeMidi: Set volume not implemented\n");
}
const HalMusicDriver _bemidi_music_driver = {
bemidi_start,
bemidi_stop,
bemidi_play_song,
bemidi_stop_song,
bemidi_is_playing,
bemidi_set_volume,
};

10
src/music/bemidi.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_BEMIDI_H
#define MUSIC_BEMIDI_H
#include "../hal.h"
extern const HalMusicDriver _bemidi_music_driver;
#endif

232
src/music/dmusic.cpp Normal file
View File

@@ -0,0 +1,232 @@
/* $Id$ */
#include "../stdafx.h"
#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
extern "C" {
#include "../openttd.h"
#include "../debug.h"
#include "../win32.h"
#include "dmusic.h"
}
#include <windows.h>
#include <dmksctrl.h>
#include <dmusici.h>
#include <dmusicc.h>
#include <dmusicf.h>
// the performance object controls manipulation of the segments
static IDirectMusicPerformance* performance = NULL;
// the loader object can load many types of DMusic related files
static IDirectMusicLoader* loader = NULL;
// the segment object is where the MIDI data is stored for playback
static IDirectMusicSegment* segment = NULL;
static bool seeking = false;
#define M(x) x "\0"
static const char ole_files[] =
M("ole32.dll")
M("CoCreateInstance")
M("CoInitialize")
M("CoUninitialize")
M("")
;
#undef M
struct ProcPtrs {
unsigned long (WINAPI * CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID* ppv);
HRESULT (WINAPI * CoInitialize)(LPVOID pvReserved);
void (WINAPI * CoUninitialize)();
};
static ProcPtrs proc;
static const char* DMusicMidiStart(const char* const* parm)
{
if (performance != NULL) return NULL;
if (proc.CoCreateInstance == NULL) {
if (!LoadLibraryList((Function*)&proc, ole_files))
return "ole32.dll load failed";
}
// Initialize COM
if (FAILED(proc.CoInitialize(NULL))) {
return "COM initialization failed";
}
// create the performance object
if (FAILED(proc.CoCreateInstance(
CLSID_DirectMusicPerformance,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicPerformance,
(LPVOID*)&performance
))) {
proc.CoUninitialize();
return "Failed to create the performance object";
}
// initialize it
if (FAILED(performance->Init(NULL, NULL, NULL))) {
performance->Release();
performance = NULL;
proc.CoUninitialize();
return "Failed to initialize performance object";
}
// choose default Windows synth
if (FAILED(performance->AddPort(NULL))) {
performance->CloseDown();
performance->Release();
performance = NULL;
proc.CoUninitialize();
return "AddPort failed";
}
// create the loader object; this will be used to load the MIDI file
if (FAILED(proc.CoCreateInstance(
CLSID_DirectMusicLoader,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicLoader,
(LPVOID*)&loader
))) {
performance->CloseDown();
performance->Release();
performance = NULL;
proc.CoUninitialize();
return "Failed to create loader object";
}
return NULL;
}
static void DMusicMidiStop(void)
{
seeking = false;
if (performance != NULL) performance->Stop(NULL, NULL, 0, 0);
if (segment != NULL) {
segment->SetParam(GUID_Unload, 0xFFFFFFFF, 0, 0, performance);
segment->Release();
segment = NULL;
}
if (performance != NULL) {
performance->CloseDown();
performance->Release();
performance = NULL;
}
if (loader != NULL) {
loader->Release();
loader = NULL;
}
proc.CoUninitialize();
}
static void DMusicMidiPlaySong(const char* filename)
{
// set up the loader object info
DMUS_OBJECTDESC obj_desc;
ZeroMemory(&obj_desc, sizeof(obj_desc));
obj_desc.dwSize = sizeof(obj_desc);
obj_desc.guidClass = CLSID_DirectMusicSegment;
obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
MultiByteToWideChar(
CP_ACP, MB_PRECOMPOSED,
filename, -1,
obj_desc.wszFileName, lengthof(obj_desc.wszFileName)
);
// release the existing segment if we have any
if (segment != NULL) {
segment->Release();
segment = NULL;
}
// make a new segment
if (FAILED(loader->GetObject(
&obj_desc, IID_IDirectMusicSegment, (LPVOID*)&segment
))) {
DEBUG(driver, 0, "DirectMusic: GetObject failed");
return;
}
// tell the segment what kind of data it contains
if (FAILED(segment->SetParam(
GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, performance
))) {
DEBUG(driver, 0, "DirectMusic: SetParam (MIDI file) failed");
return;
}
// tell the segment to 'download' the instruments
if (FAILED(segment->SetParam(GUID_Download, 0xFFFFFFFF, 0, 0, performance))) {
DEBUG(driver, 0, "DirectMusic: failed to download instruments");
return;
}
// start playing the MIDI file
if (FAILED(performance->PlaySegment(segment, 0, 0, NULL))) {
DEBUG(driver, 0, "DirectMusic: PlaySegment failed");
return;
}
seeking = true;
}
static void DMusicMidiStopSong(void)
{
if (FAILED(performance->Stop(segment, NULL, 0, 0))) {
DEBUG(driver, 0, "DirectMusic: StopSegment failed");
}
seeking = false;
}
static bool DMusicMidiIsSongPlaying(void)
{
/* Not the nicest code, but there is a short delay before playing actually
* starts. OpenTTD makes no provision for this. */
if (performance->IsPlaying(segment, NULL) == S_OK) {
seeking = false;
return true;
} else {
return seeking;
}
}
static void DMusicMidiSetVolume(byte vol)
{
// 0 - 127 -> -2000 - 0
long db = vol * 2000 / 127 - 2000;
performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db));
}
extern "C" const HalMusicDriver _dmusic_midi_driver = {
DMusicMidiStart,
DMusicMidiStop,
DMusicMidiPlaySong,
DMusicMidiStopSong,
DMusicMidiIsSongPlaying,
DMusicMidiSetVolume,
};
#endif

10
src/music/dmusic.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_DMUSIC_H
#define MUSIC_DMUSIC_H
#include "../hal.h"
extern const HalMusicDriver _dmusic_midi_driver;
#endif

108
src/music/extmidi.c Normal file
View File

@@ -0,0 +1,108 @@
/* $Id$ */
#ifndef __MORPHOS__
#include "../stdafx.h"
#include "../openttd.h"
#include "../sound.h"
#include "../string.h"
#include "../variables.h"
#include "../debug.h"
#include "extmidi.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
static struct {
char song[MAX_PATH];
pid_t pid;
} _midi;
static void DoPlay(void);
static void DoStop(void);
static const char* ExtMidiStart(const char* const * parm)
{
_midi.song[0] = '\0';
_midi.pid = -1;
return NULL;
}
static void ExtMidiStop(void)
{
_midi.song[0] = '\0';
DoStop();
}
static void ExtMidiPlaySong(const char* filename)
{
ttd_strlcpy(_midi.song, filename, lengthof(_midi.song));
DoStop();
}
static void ExtMidiStopSong(void)
{
_midi.song[0] = '\0';
DoStop();
}
static bool ExtMidiIsPlaying(void)
{
if (_midi.pid != -1 && waitpid(_midi.pid, NULL, WNOHANG) == _midi.pid)
_midi.pid = -1;
if (_midi.pid == -1 && _midi.song[0] != '\0') DoPlay();
return _midi.pid != -1;
}
static void ExtMidiSetVolume(byte vol)
{
DEBUG(driver, 1, "extmidi: set volume not implemented");
}
static void DoPlay(void)
{
_midi.pid = fork();
switch (_midi.pid) {
case 0: {
int d;
close(0);
d = open("/dev/null", O_RDONLY);
if (d != -1 && dup2(d, 1) != -1 && dup2(d, 2) != -1) {
#if defined(MIDI_ARG)
execlp(msf.extmidi, "extmidi", MIDI_ARG, _midi.song, (char*)0);
#else
execlp(msf.extmidi, "extmidi", _midi.song, (char*)0);
#endif
}
_exit(1);
}
case -1:
DEBUG(driver, 0, "extmidi: couldn't fork: %s", strerror(errno));
/* FALLTHROUGH */
default:
_midi.song[0] = '\0';
break;
}
}
static void DoStop(void)
{
if (_midi.pid != -1) kill(_midi.pid, SIGTERM);
}
const HalMusicDriver _extmidi_music_driver = {
ExtMidiStart,
ExtMidiStop,
ExtMidiPlaySong,
ExtMidiStopSong,
ExtMidiIsPlaying,
ExtMidiSetVolume,
};
#endif /* __MORPHOS__ */

10
src/music/extmidi.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_EXTERNAL_H
#define MUSIC_EXTERNAL_H
#include "../hal.h"
extern const HalMusicDriver _extmidi_music_driver;
#endif

21
src/music/null_m.c Normal file
View File

@@ -0,0 +1,21 @@
/* $Id$ */
#include "../stdafx.h"
#include "../openttd.h"
#include "null_m.h"
static const char* NullMidiStart(const char* const* parm) { return NULL; }
static void NullMidiStop(void) {}
static void NullMidiPlaySong(const char *filename) {}
static void NullMidiStopSong(void) {}
static bool NullMidiIsSongPlaying(void) { return true; }
static void NullMidiSetVolume(byte vol) {}
const HalMusicDriver _null_music_driver = {
NullMidiStart,
NullMidiStop,
NullMidiPlaySong,
NullMidiStopSong,
NullMidiIsSongPlaying,
NullMidiSetVolume,
};

10
src/music/null_m.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_NULL_H
#define MUSIC_NULL_H
#include "../hal.h"
extern const HalMusicDriver _null_music_driver;
#endif

77
src/music/os2_m.c Normal file
View File

@@ -0,0 +1,77 @@
/* $Id$ */
#include "../stdafx.h"
#include "../openttd.h"
#include "os2_m.h"
#define INCL_DOS
#define INCL_OS2MM
#define INCL_WIN
#include <stdarg.h>
#include <os2.h>
#include <os2me.h>
/**********************
* OS/2 MIDI PLAYER
**********************/
/* Interesting how similar the MCI API in OS/2 is to the Win32 MCI API,
* eh? Anyone would think they both came from the same place originally! ;)
*/
static long CDECL MidiSendCommand(const char *cmd, ...)
{
va_list va;
char buf[512];
va_start(va, cmd);
vsprintf(buf, cmd, va);
va_end(va);
return mciSendString(buf, NULL, 0, NULL, 0);
}
static void OS2MidiPlaySong(const char *filename)
{
MidiSendCommand("close all");
if (MidiSendCommand("open %s type sequencer alias song", filename) != 0)
return;
MidiSendCommand("play song from 0");
}
static void OS2MidiStopSong(void)
{
MidiSendCommand("close all");
}
static void OS2MidiSetVolume(byte vol)
{
MidiSendCommand("set song audio volume %d", ((vol/127)*100));
}
static bool OS2MidiIsSongPlaying(void)
{
char buf[16];
mciSendString("status song mode", buf, sizeof(buf), NULL, 0);
return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
}
static const char *OS2MidiStart(const char * const *parm)
{
return 0;
}
static void OS2MidiStop(void)
{
MidiSendCommand("close all");
}
const HalMusicDriver _os2_music_driver = {
OS2MidiStart,
OS2MidiStop,
OS2MidiPlaySong,
OS2MidiStopSong,
OS2MidiIsSongPlaying,
OS2MidiSetVolume,
};

10
src/music/os2_m.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_OS2_H
#define MUSIC_OS2_H
#include "../hal.h"
extern const HalMusicDriver _os2_music_driver;
#endif

371
src/music/qtmidi.c Normal file
View File

@@ -0,0 +1,371 @@
/* $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,
};

10
src/music/qtmidi.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_MACOSX_QUICKTIME_H
#define MUSIC_MACOSX_QUICKTIME_H
#include "../hal.h"
extern const HalMusicDriver _qtime_music_driver;
#endif /* !MUSIC_MACOSX_QUICKTIME_H */

170
src/music/win32_m.c Normal file
View File

@@ -0,0 +1,170 @@
/* $Id$ */
#include "../stdafx.h"
#include "../openttd.h"
#include "win32_m.h"
#include <windows.h>
#include <mmsystem.h>
static struct {
bool stop_song;
bool terminate;
bool playing;
int new_vol;
HANDLE wait_obj;
UINT_PTR devid;
char start_song[260];
} _midi;
static void Win32MidiPlaySong(const char *filename)
{
strcpy(_midi.start_song, filename);
_midi.playing = true;
_midi.stop_song = false;
SetEvent(_midi.wait_obj);
}
static void Win32MidiStopSong(void)
{
if (_midi.playing) {
_midi.stop_song = true;
_midi.start_song[0] = '\0';
SetEvent(_midi.wait_obj);
}
}
static bool Win32MidiIsSongPlaying(void)
{
return _midi.playing;
}
static void Win32MidiSetVolume(byte vol)
{
_midi.new_vol = vol;
SetEvent(_midi.wait_obj);
}
static MCIERROR CDECL MidiSendCommand(const char* cmd, ...)
{
va_list va;
char buf[512];
va_start(va, cmd);
vsprintf(buf, cmd, va);
va_end(va);
return mciSendStringA(buf, NULL, 0, 0);
}
static bool MidiIntPlaySong(const char *filename)
{
MidiSendCommand("close all");
if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0)
return false;
if (MidiSendCommand("play song from 0") != 0)
return false;
return true;
}
static void MidiIntStopSong(void)
{
MidiSendCommand("close all");
}
static void MidiIntSetVolume(int vol)
{
DWORD v = (vol * 65535 / 127);
midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16));
}
static bool MidiIntIsSongPlaying(void)
{
char buf[16];
mciSendStringA("status song mode", buf, sizeof(buf), 0);
return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
}
static DWORD WINAPI MidiThread(LPVOID arg)
{
_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL);
do {
char *s;
int vol;
vol = _midi.new_vol;
if (vol != -1) {
_midi.new_vol = -1;
MidiIntSetVolume(vol);
}
s = _midi.start_song;
if (s[0] != '\0') {
_midi.playing = MidiIntPlaySong(s);
s[0] = '\0';
// Delay somewhat in case we don't manage to play.
if (!_midi.playing) {
Sleep(5000);
}
}
if (_midi.stop_song && _midi.playing) {
_midi.stop_song = false;
_midi.playing = false;
MidiIntStopSong();
}
if (_midi.playing && !MidiIntIsSongPlaying())
_midi.playing = false;
WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000);
} while (!_midi.terminate);
DeleteObject(_midi.wait_obj);
return 0;
}
static const char *Win32MidiStart(const char * const *parm)
{
MIDIOUTCAPS midicaps;
DWORD threadId;
UINT nbdev;
UINT_PTR dev;
char buf[16];
mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0);
if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio";
memset(&_midi, 0, sizeof(_midi));
_midi.new_vol = -1;
/* Get midi device */
_midi.devid = MIDI_MAPPER;
for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) {
if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) {
_midi.devid = dev;
break;
}
}
if (CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId) == NULL)
return "Failed to create thread";
return NULL;
}
static void Win32MidiStop(void)
{
_midi.terminate = true;
SetEvent(_midi.wait_obj);
}
const HalMusicDriver _win32_music_driver = {
Win32MidiStart,
Win32MidiStop,
Win32MidiPlaySong,
Win32MidiStopSong,
Win32MidiIsSongPlaying,
Win32MidiSetVolume,
};

10
src/music/win32_m.h Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
#ifndef MUSIC_WIN32_H
#define MUSIC_WIN32_H
#include "../hal.h"
extern const HalMusicDriver _win32_music_driver;
#endif