Backend modularization: Create timer manager, savefile manager and audio mixer in the backends for increased flexibility

svn-id: r24443
This commit is contained in:
Max Horn 2006-10-22 15:42:29 +00:00
parent df24f1ef4e
commit 07f7761479
19 changed files with 134 additions and 141 deletions

View File

@ -83,6 +83,8 @@ void OSystem_PalmBase::initBackend() {
int_initBackend();
_keyMouseMask = (_keyMouse.bitUp | _keyMouse.bitDown | _keyMouse.bitLeft | _keyMouse.bitRight | _keyMouse.bitButLeft);
OSystem::initBackend();
}
uint32 OSystem_PalmBase::getMillis() {

View File

@ -52,6 +52,8 @@ OSystem_DS::~OSystem_DS() {
void OSystem_DS::initBackend() {
ConfMan.setInt("autosave_period", 0);
ConfMan.setBool("FM_low_quality", true);
OSystem::initBackend();
}
bool OSystem_DS::hasFeature(Feature f) {

View File

@ -145,6 +145,8 @@ void OSystem_GP2X::initBackend() {
SDL_ShowCursor(SDL_DISABLE);
OSystem::initBackend();
_inited = true;
}

View File

@ -33,6 +33,15 @@
#include "backends/intern.h"
namespace Audio {
class Mixer;
}
namespace Common {
class SaveFileManager;
class TimerManager;
}
#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
// Uncomment this to enable the 'on screen display' code.
#define USE_OSD 1
@ -124,9 +133,10 @@ public:
virtual bool pollEvent(Event &event); // overloaded by CE backend
// Set function that generates samples
typedef void (*SoundProc)(void *param, byte *buf, int len);
virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend
void clearSoundCallback();
virtual Audio::Mixer *getMixer();
// Poll CD status
// Returns true if cd audio is playing
@ -146,7 +156,9 @@ public:
// Add a callback timer
typedef int (*TimerProc)(int interval);
void setTimerCallback(TimerProc callback, int timer);
virtual Common::TimerManager *getTimerManager();
// Mutex handling
MutexRef createMutex();
@ -187,6 +199,8 @@ public:
void displayMessageOnOSD(const char *msg);
#endif
virtual Common::SaveFileManager *getSavefileManager();
protected:
bool _inited;
@ -357,6 +371,12 @@ protected:
MutexRef _graphicsMutex;
Common::SaveFileManager *_savefile;
Audio::Mixer *_mixer;
Common::TimerManager *_timer;
void addDirtyRgnAuto(const byte *buf);
void makeChecksums(const byte *buf);

View File

@ -27,6 +27,10 @@
#include "common/util.h"
#include "base/main.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
#include "sound/mixer.h"
#include "icons/scummvm.xpm"
#if defined(__SYMBIAN32__)
@ -42,6 +46,11 @@ int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpC
}
#endif
static int timer_handler(int t) {
DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager();
return tm->handler(t);
}
int main(int argc, char *argv[]) {
#if defined(__SYMBIAN32__)
@ -169,6 +178,29 @@ void OSystem_SDL::initBackend() {
printf("Using joystick: %s\n", SDL_JoystickName(0));
_joystick = SDL_JoystickOpen(joystick_num);
}
// Create the savefile manager, if none exists yet (we check for this to
// allow subclasses to provide their own).
if (_savefile == 0) {
_savefile = new DefaultSaveFileManager();
}
// Create and hook up the mixer, if none exists yet (we check for this to
// allow subclasses to provide their own).
if (_mixer == 0) {
_mixer = new Audio::Mixer();
setSoundCallback(Audio::Mixer::mixCallback, _mixer);
}
// Create and hook up the timer manager, if none exists yet (we check for
// this to allow subclasses to provide their own).
if (_timer == 0) {
_timer = new DefaultTimerManager();
setTimerCallback(&timer_handler, 10);
}
OSystem::initBackend();
_inited = true;
}
@ -189,6 +221,9 @@ OSystem_SDL::OSystem_SDL()
_joystick(0),
_currentShakePos(0), _newShakePos(0),
_paletteDirtyStart(0), _paletteDirtyEnd(0),
_savefile(0),
_mixer(0),
_timer(0),
_graphicsMutex(0), _transactionMode(kTransactionNone) {
// allocate palette storage
@ -223,6 +258,16 @@ void OSystem_SDL::setTimerCallback(TimerProc callback, int timer) {
SDL_SetTimer(timer, (SDL_TimerCallback) callback);
}
Common::TimerManager *OSystem_SDL::getTimerManager() {
assert(_timer);
return _timer;
}
Common::SaveFileManager *OSystem_SDL::getSavefileManager() {
assert(_savefile);
return _savefile;
}
void OSystem_SDL::setWindowCaption(const char *caption) {
SDL_WM_SetCaption(caption, caption);
}
@ -395,6 +440,7 @@ bool OSystem_SDL::setSoundCallback(SoundProc proc, void *param) {
// least on some platforms SDL will lie and claim it did get the rate
// even if it didn't. Probably only happens for "weird" rates, though.
_samplesPerSec = obtained.freq;
debug(1, "Output sample rate: %d Hz", _samplesPerSec);
SDL_PauseAudio(0);
return true;
}
@ -407,6 +453,11 @@ int OSystem_SDL::getOutputSampleRate() const {
return _samplesPerSec;
}
Audio::Mixer *OSystem_SDL::getMixer() {
assert(_mixer);
return _mixer;
}
#pragma mark -
#pragma mark --- CD Audio ---
#pragma mark -

View File

@ -246,6 +246,12 @@ void OSystem_WINCE3::initBackend()
GUI_Actions::Instance()->loadMapping();
loadDeviceConfiguration();
// FIXME: We are currently not calling OSystem_SDL::initBackend() here.
// Maybe on purpose, but this is possibly a bit risky... E.g. _inited
// won't be set correctly due to this... Can we change this? Maybe after
// some changes to the base SDL backend?
//OSystem_SDL::initBackend();
}
int OSystem_WINCE3::getScreenWidth() {

View File

@ -205,7 +205,8 @@ out_of_loop:
/* And finally start the local timer */
gettimeofday(&_start_time, NULL);
OSystem::initBackend();
}
#undef CAPTURE_SOUND

View File

@ -25,61 +25,34 @@
#include "common/util.h"
#include "common/system.h"
namespace Common {
// FIXME: Hack: This global variable shouldn't be declared here; in fact it
// probably shouldn't be declared at all but rather a different method to
// query the TimerManager object should be invented.
TimerManager *g_timer = NULL;
}
DefaultTimerManager::DefaultTimerManager(OSystem *system) :
_system(system),
DefaultTimerManager::DefaultTimerManager() :
_timerHandler(0),
_lastTime(0) {
Common::g_timer = this;
for (int i = 0; i < MAX_TIMERS; i++) {
_timerSlots[i].procedure = NULL;
_timerSlots[i].interval = 0;
_timerSlots[i].counter = 0;
}
_thisTime = _system->getMillis();
// Set the timer last, after everything has been initialised
_system->setTimerCallback(&timer_handler, 10);
_thisTime = g_system->getMillis();
}
DefaultTimerManager::~DefaultTimerManager() {
// Remove the timer callback.
// Note: backends *must* gurantee that after this method call returns,
// the handler is not in use anymore; else race condtions could occur.
_system->setTimerCallback(0, 0);
{
Common::StackLock lock(_mutex);
for (int i = 0; i < MAX_TIMERS; i++) {
_timerSlots[i].procedure = NULL;
_timerSlots[i].interval = 0;
_timerSlots[i].counter = 0;
}
Common::StackLock lock(_mutex);
for (int i = 0; i < MAX_TIMERS; i++) {
_timerSlots[i].procedure = NULL;
_timerSlots[i].interval = 0;
_timerSlots[i].counter = 0;
}
}
int DefaultTimerManager::timer_handler(int t) {
if (Common::g_timer)
return ((DefaultTimerManager *)Common::g_timer)->handler(t);
return 0;
}
int DefaultTimerManager::handler(int t) {
Common::StackLock lock(_mutex);
uint32 interval, l;
_lastTime = _thisTime;
_thisTime = _system->getMillis();
_thisTime = g_system->getMillis();
interval = 1000 * (_thisTime - _lastTime);
for (l = 0; l < MAX_TIMERS; l++) {

View File

@ -32,7 +32,6 @@ private:
enum {
MAX_TIMERS = 8
};
OSystem *_system;
Common::Mutex _mutex;
void *_timerHandler;
int32 _thisTime;
@ -46,13 +45,12 @@ private:
} _timerSlots[MAX_TIMERS];
public:
DefaultTimerManager(OSystem *system);
DefaultTimerManager();
~DefaultTimerManager();
bool installTimerProc(TimerProc proc, int32 interval, void *refCon);
void removeTimerProc(TimerProc proc);
protected:
static int timer_handler(int t);
// Timer callback, to be invoked at regular time intervals by the backend.
int handler(int t);
};

View File

@ -35,16 +35,12 @@
#include "base/plugins.h"
#include "base/version.h"
#include "backends/timer/default/default-timer.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/system.h"
#include "common/timer.h"
#include "gui/newgui.h"
#include "gui/message.h"
#include "sound/mididrv.h"
#include "sound/mixer.h"
#if defined(_WIN32_WCE)
#include "backends/platform/wince/CELauncherDialog.h"
@ -227,10 +223,6 @@ static int runGame(const Plugin *plugin, OSystem &system, const Common::String &
}
// FIXME: Temporary hack, to be removed soon
Audio::Mixer *g_mixer = 0;
extern "C" int scummvm_main(int argc, char *argv[]) {
Common::String specialDebug;
Common::String command;
@ -288,11 +280,6 @@ extern "C" int scummvm_main(int argc, char *argv[]) {
// the command line params) was read.
system.initBackend();
// Create the timer services
Common::g_timer = new DefaultTimerManager(&system);
g_mixer = new Audio::Mixer();
// Set initial window caption
system.setWindowCaption(gScummVMFullVersion);
@ -336,11 +323,5 @@ extern "C" int scummvm_main(int argc, char *argv[]) {
launcherDialog(system);
}
// Deinit the mixer
delete g_mixer;
// Deinit the timer
delete Common::g_timer;
return 0;
}

View File

@ -27,13 +27,13 @@
#include "gui/message.h"
#include "backends/saves/default/default-saves.h"
#include "common/config-manager.h"
#include "common/system.h"
#include "common/timer.h"
#include "common/util.h"
#include "sound/mixer.h"
OSystem *g_system = 0;
bool OSystem::setGraphicsMode(const char *name) {
@ -63,23 +63,6 @@ void OSystem::displayMessageOnOSD(const char *msg) {
dialog.runModal();
}
Common::SaveFileManager *OSystem::getSavefileManager() {
// TODO: Change this to always return the same
// instance, instead of a new one each time around...
return new DefaultSaveFileManager();
}
Audio::Mixer *OSystem::getMixer() {
// FIXME
extern Audio::Mixer *g_mixer;
return g_mixer;
}
Common::TimerManager *OSystem::getTimerManager() {
// FIXME
return Common::g_timer;
}
bool OSystem::openCD(int drive) {
return false;

View File

@ -66,6 +66,10 @@ public:
/**
* The following method is called once, from main.cpp, after all
* config data (including command line params etc.) are fully loaded.
*
* @note Subclasses should always invoke the implementation of their
* parent class. They should so so near the end of their own
* implementation.
*/
virtual void initBackend() { }
@ -675,8 +679,6 @@ public:
/** @name Events and Time */
//@{
typedef int (*TimerProc)(int interval);
/**
* The types of events backends may generate.
* @see Event
@ -798,24 +800,10 @@ public:
virtual void delayMillis(uint msecs) = 0;
/**
* Set the timer callback, a function which is periodically invoked by the
* backend. This can for example be done via a background thread.
* There is at most one active timer; if this method is called while there
* is already an active timer, then the new timer callback should replace
* the previous one. In particular, passing a callback pointer value of 0
* is legal and can be used to clear the current timer callback.
* @see Common::Timer
* @note The implementation of this method must be 'atomic' in the sense
* that when the method returns, the previously set callback must
* not be in use anymore (in particular, if timers are implemented
* via threads, then it must be ensured that the timer thread is
* not using the old callback function anymore).
*
* @param callback pointer to the callback. May be 0 to reset the timer
* @param interval the interval (in milliseconds) between invocations
* of the callback
* Returh the timer manager. For more information, refer to the
* TimerManager documentation.
*/
virtual void setTimerCallback(TimerProc callback, int interval) = 0;
virtual Common::TimerManager *getTimerManager() = 0;
//@}
@ -870,22 +858,12 @@ public:
/** @name Sound */
//@{
typedef void (*SoundProc)(void *param, byte *buf, int len);
/**
* Set the audio callback which is invoked whenever samples need to be generated.
* Currently, only the 16-bit signed mode is ever used for Simon & Scumm
* @param proc pointer to the callback.
* @param param an arbitrary parameter which is stored and passed to proc.
* Returh the audio mixer. For more information, refer to the
* Audio::Mixer documentation.
*/
virtual bool setSoundCallback(SoundProc proc, void *param) = 0;
/**
* Remove any audio callback previously set via setSoundCallback, thus effectively
* stopping all audio output immediately.
* @see setSoundCallback
*/
virtual void clearSoundCallback() = 0;
virtual Audio::Mixer *getMixer() = 0;
/**
* Determine the output sample rate. Audio data provided by the sound
@ -972,15 +950,12 @@ public:
*/
virtual void displayMessageOnOSD(const char *msg);
/** Savefile management. */
virtual Common::SaveFileManager *getSavefileManager();
/** TODO */
virtual Audio::Mixer *getMixer();
/** TODO */
virtual Common::TimerManager *getTimerManager();
/**
* Return the SaveFileManager, used to store and load savestates
* and other modifiable persistent game data. For more information,
* refer to the TimerManager documentation.
*/
virtual Common::SaveFileManager *getSavefileManager() = 0;
//@}
};
@ -989,5 +964,4 @@ public:
/** The global OSystem instance. Initialised in main(). */
extern OSystem *g_system;
#endif

View File

@ -52,8 +52,6 @@ public:
virtual void removeTimerProc(TimerProc proc) = 0;
};
extern TimerManager *g_timer;
} // End of namespace Common
#endif

View File

@ -48,7 +48,7 @@ Render::Render(SagaEngine *vm, OSystem *system) {
_initialized = false;
// Initialize FPS timer callback
Common::g_timer->installTimerProc(&fpsTimerCallback, 1000000, this);
_vm->_timer->installTimerProc(&fpsTimerCallback, 1000000, this);
_backGroundSurface.create(_vm->getDisplayWidth(), _vm->getDisplayHeight(), 1);
@ -58,7 +58,7 @@ Render::Render(SagaEngine *vm, OSystem *system) {
}
Render::~Render(void) {
Common::g_timer->removeTimerProc(&fpsTimerCallback);
_vm->_timer->removeTimerProc(&fpsTimerCallback);
_backGroundSurface.free();
_initialized = false;

View File

@ -308,7 +308,7 @@ void SmushPlayer::init(int32 speed) {
_vm->_mixer->stopHandle(_IACTchannel);
_vm->_smixer->stop();
Common::g_timer->installTimerProc(&timerCallback, 1000000 / _speed, this);
_vm->_timer->installTimerProc(&timerCallback, 1000000 / _speed, this);
_initDone = true;
}

View File

@ -119,23 +119,20 @@ Mixer::Mixer() {
for (i = 0; i != NUM_CHANNELS; i++)
_channels[i] = 0;
_mixerReady = _syst->setSoundCallback(mixCallback, this);
_outputRate = (uint)_syst->getOutputSampleRate();
if (_outputRate == 0)
error("OSystem returned invalid sample rate");
debug(1, "Output sample rate: %d Hz", _outputRate);
_mixerReady = false;
}
Mixer::~Mixer() {
_syst->clearSoundCallback();
stopAll(true);
delete _premixChannel;
_premixChannel = 0;
}
uint Mixer::getOutputRate() const {
return (uint)_syst->getOutputSampleRate();
}
bool Mixer::isPaused() {
return _paused;
}
@ -238,6 +235,9 @@ void Mixer::playInputStream(SoundType type, SoundHandle *handle, AudioStream *in
void Mixer::mix(int16 *buf, uint len) {
Common::StackLock lock(_mutex);
// Since the mixer callback has been called, the mixer must be ready...
_mixerReady = true;
// zero the buf
memset(buf, 0, 2 * len * sizeof(int16));

View File

@ -94,8 +94,6 @@ private:
Channel *_premixChannel;
uint _outputRate;
int _volumeForSoundType[4];
bool _paused;
@ -292,9 +290,9 @@ public:
*
* @return the output sample rate in Hz
*/
uint getOutputRate() const { return _outputRate; }
uint getOutputRate() const;
private:
protected:
void insertChannel(SoundHandle *handle, Channel *chan);
/**
@ -302,6 +300,9 @@ private:
*/
void mix(int16 * buf, uint len);
// FIXME: temporary "public" to allow access to mixCallback
// from within OSystem::makeMixer()
public:
/**
* The mixer callback function, passed on to OSystem::setSoundCallback().
* This simply calls the mix() method.

View File

@ -42,7 +42,8 @@ void ProtrackerPlayer::init(OSystem *system) {
// subclass and hook that with the mixer. See also the
// code used by other softsynths (sound/softsynth/emumidi.h).
_system->setSoundCallback(&audioCallback, this);
// _system->setSoundCallback(&audioCallback, this);
error("ProtrackerPlayer::init -- setSoundCallback is no more");
}
void ProtrackerPlayer::start() {

View File

@ -424,10 +424,10 @@ void MidiDriver_ThreadedMT32::close() {
void MidiDriver_ThreadedMT32::setTimerCallback(void *timer_param, TimerManager::TimerProc timer_proc) {
if (!_timer_proc || !timer_proc) {
if (_timer_proc)
g_timer->removeTimerProc(_timer_proc);
_vm->_timer->removeTimerProc(_timer_proc);
_timer_proc = timer_proc;
if (timer_proc)
g_timer->installTimerProc(timer_proc, getBaseTempo(), timer_param);
_vm->_timer->installTimerProc(timer_proc, getBaseTempo(), timer_param);
}
}