SCI: Some SFX player cleanup

svn-id: r40956
This commit is contained in:
Max Horn 2009-05-28 10:29:11 +00:00
parent 78b3c80b11
commit 01252c4aaf
4 changed files with 107 additions and 145 deletions

View File

@ -58,7 +58,7 @@ void sfx_reset_player() {
int sfx_get_player_polyphony() {
if (player)
return player->polyphony;
return player->_polyphony;
else
return 0;
}
@ -344,14 +344,6 @@ int sfx_play_iterator_pcm(SongIterator *it, song_handle_t handle) {
#define DELAY (1000000 / SFX_TICKS_PER_SEC)
static void _sfx_timer_callback(void *data) {
/* First run the player, to give it a chance to fill
** the audio buffer */
if (player)
player->maintenance();
}
void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {
song_lib_init(&self->songlib);
self->song = NULL;
@ -360,18 +352,13 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {
self->soundSync = NULL;
self->audioResource = NULL;
player = NULL;
if (flags & SFX_STATE_FLAG_NOSOUND) {
player = NULL;
sciprintf("[SFX] Sound disabled.\n");
warning("[SFX] Sound disabled");
return;
}
// TODO: Implement platform policy here?
player = new NewPlayer();
//player = new PolledPlayer();
//player = new RealtimePlayer();
#ifdef DEBUG_SONG_API
fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags);
#endif
@ -381,67 +368,36 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {
/*-------------------*/
if (!resmgr) {
sciprintf("[SFX] Warning: No resource manager present, cannot initialise player\n");
player = NULL;
} else if (player->init(resmgr, DELAY / 1000)) {
sciprintf("[SFX] Song player '%s' reported error, disabled\n", player->name);
delete player;
player = NULL;
warning("[SFX] Warning: No resource manager present, cannot initialise player");
return;
}
if (!player)
player = new NewPlayer();
if (!player) {
sciprintf("[SFX] No song player found\n");
else
sciprintf("[SFX] Using song player '%s', v%s\n", player->name, player->version);
return;
}
/*------------------*/
/* Initialise timer */
/*------------------*/
// We initialise the timer last, so there is no possibility of the
// timer callback being triggered while the mixer or player are
// still being initialized.
if (strcmp(player->name, "realtime") == 0) {
// FIXME: Merge this timer code into RealtimePlayer itself
if (!g_system->getTimerManager()->installTimerProc(&_sfx_timer_callback, DELAY, NULL)) {
warning("[SFX] " __FILE__": Timer failed to initialize");
warning("[SFX] Disabled sound support");
delete player;
player = NULL;
}
if (player->init(resmgr, DELAY / 1000)) {
warning("[SFX] Song player reported error, disabled");
delete player;
player = NULL;
}
}
void sfx_exit(sfx_state_t *self) {
g_system->getTimerManager()->removeTimerProc(&_sfx_timer_callback);
// The timer API guarantees no more callbacks are running or will be
// run from this point onward, so we can now safely exit the mixer and
// player.
#ifdef DEBUG_SONG_API
fprintf(stderr, "[sfx-core] Uninitialising\n");
#endif
// WARNING: The mixer may hold feeds from the player, so we must
// stop the mixer BEFORE stopping the player.
// FIXME Player "new" frees its own feeds, so we only need to stop any
// remaining sfx feeds after stopping the player.
if (strcmp(player->name, "new") != 0)
g_system->getMixer()->stopAll();
// FIXME: change players to stop their own audio streams
if (player) {
// See above: This must happen AFTER stopping the mixer
player->exit();
delete player;
player = 0;
}
// FIXME: player is deleted here by the code above, so this will crash.
// Is that code needed?
//if (strcmp(player->name, "new") == 0)
// g_system->getMixer()->stopAll();
g_system->getMixer()->stopAll();
song_lib_free(self->songlib);

View File

@ -37,14 +37,11 @@ namespace Sci {
class SfxPlayer {
public:
const char *name;
const char *version;
/** Number of voices that can play simultaneously */
int polyphony;
int _polyphony;
public:
SfxPlayer() : name(0), version(0), polyphony(0) {}
SfxPlayer() : _polyphony(0) {}
virtual ~SfxPlayer() {}
virtual Common::Error init(ResourceManager *resmgr, int expected_latency) = 0;
@ -96,12 +93,6 @@ public:
** Returns : (int) Common::kNoError on success, Common::kUnknownError on failure
*/
virtual void maintenance() {}
/* Regularly called maintenance function
** This function is called frequently and regularly (if present), it can be
** used to emit sound.
*/
virtual void tell_synth(int buf_nr, byte *buf) = 0;
/* Pass a raw MIDI event to the synth
Parameters: (int) argc: Length of buffer holding the midi event

View File

@ -36,37 +36,36 @@
namespace Sci {
// TODO: Turn the following static vars into member vars
static MidiPlayer *mididrv;
NewPlayer::NewPlayer() {
_mididrv = 0;
static SongIterator *play_it = NULL;
static Audio::Timestamp wakeup_time;
static Audio::Timestamp current_time;
static uint32 play_pause_diff;
_iterator = NULL;
_pauseTimeDiff = 0;
static int play_paused = 0;
static int play_it_done = 0;
static uint32 tempo;
_paused = false;
_iteratorIsDone = false;
_tempo = 0;
static Common::Mutex *mutex;
static int volume = 15;
_mutex = 0;
_volume = 15;
}
static void play_song(SongIterator *it) {
while (play_it && wakeup_time.msecsDiff(current_time) <= 0) {
void NewPlayer::play_song(SongIterator *it) {
while (_iterator && _wakeupTime.msecsDiff(_currentTime) <= 0) {
int delay;
byte buf[8];
int result;
switch ((delay = songit_next(&(play_it),
switch ((delay = songit_next(&(_iterator),
buf, &result,
IT_READER_MASK_ALL
| IT_READER_MAY_FREE
| IT_READER_MAY_CLEAN))) {
case SI_FINISHED:
delete play_it;
play_it = NULL;
play_it_done = 1;
delete _iterator;
_iterator = NULL;
_iteratorIsDone = true;
return;
case SI_IGNORE:
@ -76,16 +75,16 @@ static void play_song(SongIterator *it) {
break;
case SI_PCM:
sfx_play_iterator_pcm(play_it, 0);
sfx_play_iterator_pcm(_iterator, 0);
break;
case 0:
static_cast<MidiDriver *>(mididrv)->send(buf[0], buf[1], buf[2]);
static_cast<MidiDriver *>(_mididrv)->send(buf[0], buf[1], buf[2]);
break;
default:
wakeup_time = wakeup_time.addFrames(delay);
_wakeupTime = _wakeupTime.addFrames(delay);
}
}
}
@ -94,17 +93,19 @@ void NewPlayer::tell_synth(int buf_nr, byte *buf) {
byte op1 = (buf_nr < 2 ? 0 : buf[1]);
byte op2 = (buf_nr < 3 ? 0 : buf[2]);
static_cast<MidiDriver *>(mididrv)->send(buf[0], op1, op2);
static_cast<MidiDriver *>(_mididrv)->send(buf[0], op1, op2);
}
static void player_timer_callback(void *refCon) {
Common::StackLock lock(*mutex);
void NewPlayer::player_timer_callback(void *refCon) {
NewPlayer *player = (NewPlayer *)refCon;
assert(refCon);
Common::StackLock lock(*player->_mutex);
if (play_it && !play_it_done && !play_paused) {
play_song(play_it);
if (player->_iterator && !player->_iteratorIsDone && !player->_paused) {
player->play_song(player->_iterator);
}
current_time = current_time.addFrames(1);
player->_currentTime = player->_currentTime.addFrames(1);
}
/* API implementation */
@ -114,111 +115,104 @@ Common::Error NewPlayer::init(ResourceManager *resmgr, int expected_latency) {
switch(musicDriver) {
case MD_ADLIB:
mididrv = new MidiPlayer_Adlib();
_mididrv = new MidiPlayer_Adlib();
break;
case MD_PCJR:
mididrv = new MidiPlayer_PCJr();
_mididrv = new MidiPlayer_PCJr();
break;
case MD_PCSPK:
mididrv = new MidiPlayer_PCSpeaker();
_mididrv = new MidiPlayer_PCSpeaker();
break;
default:
break;
}
assert(mididrv);
assert(_mididrv);
this->polyphony = mididrv->getPolyphony();
_polyphony = _mididrv->getPolyphony();
tempo = mididrv->getBaseTempo();
_tempo = _mididrv->getBaseTempo();
uint32 time = g_system->getMillis();
current_time = Audio::Timestamp(time, 1000000 / tempo);
wakeup_time = Audio::Timestamp(time, SFX_TICKS_PER_SEC);
_currentTime = Audio::Timestamp(time, 1000000 / _tempo);
_wakeupTime = Audio::Timestamp(time, SFX_TICKS_PER_SEC);
mutex = new Common::Mutex();
_mutex = new Common::Mutex();
mididrv->setTimerCallback(NULL, player_timer_callback);
mididrv->open(resmgr);
mididrv->setVolume(volume);
_mididrv->setTimerCallback(this, player_timer_callback);
_mididrv->open(resmgr);
_mididrv->setVolume(_volume);
return Common::kNoError;
}
Common::Error NewPlayer::add_iterator(SongIterator *it, uint32 start_time) {
mutex->lock();
SIMSG_SEND(it, SIMSG_SET_PLAYMASK(mididrv->getPlayMask()));
SIMSG_SEND(it, SIMSG_SET_RHYTHM(mididrv->hasRhythmChannel()));
Common::StackLock lock(*_mutex);
SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayMask()));
SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel()));
if (play_it == NULL) {
if (_iterator == NULL) {
// Resync with clock
current_time = Audio::Timestamp(g_system->getMillis(), 1000000 / tempo);
wakeup_time = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
_currentTime = Audio::Timestamp(g_system->getMillis(), 1000000 / _tempo);
_wakeupTime = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
}
play_it = sfx_iterator_combine(play_it, it);
play_it_done = 0;
mutex->unlock();
_iterator = sfx_iterator_combine(_iterator, it);
_iteratorIsDone = false;
return Common::kNoError;
}
Common::Error NewPlayer::stop(void) {
debug(3, "Player: Stopping song iterator %p", (void *)play_it);
mutex->lock();
delete play_it;
play_it = NULL;
debug(3, "Player: Stopping song iterator %p", (void *)_iterator);
Common::StackLock lock(*_mutex);
delete _iterator;
_iterator = NULL;
for (int i = 0; i < MIDI_CHANNELS; i++)
static_cast<MidiDriver *>(mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
mutex->unlock();
static_cast<MidiDriver *>(_mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
return Common::kNoError;
}
Common::Error NewPlayer::iterator_message(const SongIterator::Message &msg) {
Common::StackLock lock(*mutex);
if (!play_it) {
Common::StackLock lock(*_mutex);
if (!_iterator) {
return Common::kUnknownError;
}
songit_handle_message(&play_it, msg);
songit_handle_message(&_iterator, msg);
return Common::kNoError;
}
Common::Error NewPlayer::pause(void) {
Common::StackLock lock(*mutex);
Common::StackLock lock(*_mutex);
play_paused = 1;
play_pause_diff = wakeup_time.msecsDiff(current_time);
_paused = true;
_pauseTimeDiff = _wakeupTime.msecsDiff(_currentTime);
mididrv->playSwitch(false);
_mididrv->playSwitch(false);
return Common::kNoError;
}
Common::Error NewPlayer::resume(void) {
Common::StackLock lock(*mutex);
Common::StackLock lock(*_mutex);
wakeup_time = Audio::Timestamp(current_time.msecs() + play_pause_diff, SFX_TICKS_PER_SEC);
mididrv->playSwitch(true);
play_paused = 0;
_wakeupTime = Audio::Timestamp(_currentTime.msecs() + _pauseTimeDiff, SFX_TICKS_PER_SEC);
_mididrv->playSwitch(true);
_paused = false;
return Common::kNoError;
}
Common::Error NewPlayer::exit(void) {
mididrv->close();
delete mididrv;
delete mutex;
delete play_it;
play_it = NULL;
_mididrv->close();
delete _mididrv;
delete _mutex;
delete _iterator;
_iterator = NULL;
return Common::kNoError;
}
NewPlayer::NewPlayer() {
name = "new";
version = "0.1";
}
} // End of namespace Sci

View File

@ -30,7 +30,28 @@
namespace Sci {
class MidiPlayer;
class SongIterator;
class NewPlayer : public SfxPlayer {
protected:
MidiPlayer *_mididrv;
SongIterator *_iterator;
Audio::Timestamp _wakeupTime;
Audio::Timestamp _currentTime;
uint32 _pauseTimeDiff;
bool _paused;
bool _iteratorIsDone;
uint32 _tempo;
Common::Mutex *_mutex;
int _volume;
void play_song(SongIterator *it);
static void player_timer_callback(void *refCon);
public:
NewPlayer();