mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-20 00:41:12 +00:00
SCI: Rewrote handling of song wakeup times & (iterator) delays, to avoid rounding issues between ticks (1/60s) and milliseconds; also fixed a bug (coming from Glutton ;) where delays measured in millisecs were treated as ticks instead. Thanks to Walter for the precursor of this patch
svn-id: r39263
This commit is contained in:
parent
77b40251ca
commit
4e6a7d83d1
@ -505,7 +505,7 @@ int read_song_tp(Common::SeekableReadStream *fh, song_t **foo, const char *lastv
|
||||
*foo = (song_t*) malloc(sizeof(song_t));
|
||||
token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
|
||||
%CFSMLREAD song_t (*foo) FROM fh ERRVAR *hiteof FIRSTTOKEN token LINECOUNTER *line;
|
||||
(*foo)->delay = 0;
|
||||
(*foo)->_delay = 0;
|
||||
(*foo)->it = NULL;
|
||||
(*foo)->next_playing = (*foo)->next_stopping = (*foo)->next = NULL;
|
||||
return 0;
|
||||
|
@ -4129,7 +4129,7 @@ int read_song_tp(Common::SeekableReadStream *fh, song_t **foo, const char *lastv
|
||||
}
|
||||
// End of auto-generated CFSML data reader code
|
||||
#line 508 "engines/sci/engine/savegame.cfsml"
|
||||
(*foo)->delay = 0;
|
||||
(*foo)->_delay = 0;
|
||||
(*foo)->it = NULL;
|
||||
(*foo)->next_playing = (*foo)->next_stopping = (*foo)->next = NULL;
|
||||
return 0;
|
||||
|
@ -73,14 +73,13 @@ int sfx_get_player_polyphony() {
|
||||
|
||||
static void _freeze_time(sfx_state_t *self) {
|
||||
/* Freezes the top song delay time */
|
||||
uint32 ctime = g_system->getMillis();
|
||||
const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
|
||||
song_t *song = self->song;
|
||||
|
||||
while (song) {
|
||||
if (ctime > song->wakeup_time)
|
||||
song->delay = 0;
|
||||
else
|
||||
song->delay = song->wakeup_time - ctime;
|
||||
song->_delay = song->_wakeupTime.frameDiff(ctime);
|
||||
if (song->_delay < 0)
|
||||
song->_delay = 0;
|
||||
|
||||
song = song->next_playing;
|
||||
}
|
||||
@ -132,11 +131,11 @@ static void _dump_songs(sfx_state_t *self) {
|
||||
|
||||
static void _thaw_time(sfx_state_t *self) {
|
||||
/* inverse of _freeze_time() */
|
||||
uint32 ctime = g_system->getMillis();
|
||||
const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
|
||||
song_t *song = self->song;
|
||||
|
||||
while (song) {
|
||||
song->wakeup_time = ctime + song->delay;
|
||||
song->_wakeupTime = ctime.addFrames(song->_delay);
|
||||
|
||||
song = song->next_playing;
|
||||
}
|
||||
@ -156,21 +155,21 @@ static int is_playing(sfx_state_t *self, song_t *song) {
|
||||
}
|
||||
|
||||
static void _sfx_set_song_status(sfx_state_t *self, song_t *song, int status) {
|
||||
const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
|
||||
|
||||
switch (status) {
|
||||
|
||||
case SOUND_STATUS_STOPPED:
|
||||
/* Reset */
|
||||
// Reset
|
||||
song->it->init();
|
||||
break;
|
||||
|
||||
case SOUND_STATUS_SUSPENDED:
|
||||
case SOUND_STATUS_WAITING:
|
||||
if (song->status == SOUND_STATUS_PLAYING) {
|
||||
/* Update delay, set wakeup_time */
|
||||
uint32 time = g_system->getMillis();
|
||||
|
||||
song->delay -= long(time) - long(song->wakeup_time);
|
||||
song->wakeup_time = time;
|
||||
// Update delay, set wakeup_time
|
||||
song->_delay += song->_wakeupTime.frameDiff(ctime);
|
||||
song->_wakeupTime = ctime;
|
||||
}
|
||||
if (status == SOUND_STATUS_SUSPENDED)
|
||||
break;
|
||||
@ -178,9 +177,10 @@ static void _sfx_set_song_status(sfx_state_t *self, song_t *song, int status) {
|
||||
/* otherwise... */
|
||||
|
||||
case SOUND_STATUS_PLAYING:
|
||||
if (song->status == SOUND_STATUS_STOPPED)
|
||||
/* Starting anew */
|
||||
song->wakeup_time = g_system->getMillis();
|
||||
if (song->status == SOUND_STATUS_STOPPED) {
|
||||
// Starting anew
|
||||
song->_wakeupTime = ctime;
|
||||
}
|
||||
|
||||
if (is_playing(self, song))
|
||||
status = SOUND_STATUS_PLAYING;
|
||||
@ -244,10 +244,9 @@ static void _update_single_song(sfx_state_t *self) {
|
||||
_thaw_time(self); /* Recover song delay time */
|
||||
|
||||
if (newsong && player) {
|
||||
SongIterator *clonesong
|
||||
= songit_clone(newsong->it, newsong->delay);
|
||||
SongIterator *clonesong = songit_clone(newsong->it, newsong->_delay);
|
||||
|
||||
player->add_iterator(clonesong, newsong->wakeup_time);
|
||||
player->add_iterator(clonesong, newsong->_wakeupTime.msecs());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,15 +309,13 @@ static void _update_multi_song(sfx_state_t *self) {
|
||||
oldseeker->next_playing = NULL; /* Clear this pointer; we don't need the tag anymore */
|
||||
}
|
||||
|
||||
for (newseeker = newsong; newseeker;
|
||||
newseeker = newseeker->next_playing) {
|
||||
for (newseeker = newsong; newseeker; newseeker = newseeker->next_playing) {
|
||||
if (newseeker->status != SOUND_STATUS_PLAYING && player) {
|
||||
if (self->debug & SFX_DEBUG_SONGS)
|
||||
sciprintf("[SFX] Adding song %lx\n", newseeker->it->ID);
|
||||
|
||||
player->add_iterator(songit_clone(newseeker->it,
|
||||
newseeker->delay),
|
||||
g_system->getMillis());
|
||||
SongIterator *clonesong = songit_clone(newseeker->it, newseeker->_delay);
|
||||
player->add_iterator(clonesong, g_system->getMillis());
|
||||
}
|
||||
_sfx_set_song_status(self, newseeker,
|
||||
SOUND_STATUS_PLAYING);
|
||||
@ -351,8 +348,7 @@ int sfx_play_iterator_pcm(SongIterator *it, song_handle_t handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FREQ 60
|
||||
#define DELAY (1000000 / FREQ)
|
||||
#define DELAY (1000000 / SFX_TICKS_PER_SEC)
|
||||
|
||||
|
||||
static void _sfx_timer_callback(void *data) {
|
||||
@ -483,7 +479,7 @@ int sfx_poll(sfx_state_t *self, song_handle_t *handle, int *cue) {
|
||||
}
|
||||
|
||||
int sfx_poll_specific(sfx_state_t *self, song_handle_t handle, int *cue) {
|
||||
uint32 ctime = g_system->getMillis();
|
||||
const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
|
||||
song_t *song = self->song;
|
||||
|
||||
while (song && song->handle != handle)
|
||||
@ -497,13 +493,11 @@ int sfx_poll_specific(sfx_state_t *self, song_handle_t handle, int *cue) {
|
||||
}
|
||||
|
||||
while (1) {
|
||||
unsigned char buf[8];
|
||||
int result;
|
||||
|
||||
if (song->wakeup_time > ctime)
|
||||
if (song->_wakeupTime.frameDiff(ctime) > 0)
|
||||
return 0; /* Patience, young hacker! */
|
||||
|
||||
result = songit_next(&(song->it), buf, cue, IT_READER_MASK_ALL);
|
||||
unsigned char buf[8];
|
||||
int result = songit_next(&(song->it), buf, cue, IT_READER_MASK_ALL);
|
||||
|
||||
switch (result) {
|
||||
|
||||
@ -532,7 +526,7 @@ int sfx_poll_specific(sfx_state_t *self, song_handle_t handle, int *cue) {
|
||||
|
||||
default:
|
||||
if (result > 0)
|
||||
song->wakeup_time += result * SOUND_TICK;
|
||||
song->_wakeupTime = song->_wakeupTime.addFrames(result);
|
||||
|
||||
/* Delay */
|
||||
break;
|
||||
@ -587,7 +581,7 @@ int sfx_add_song(sfx_state_t *self, SongIterator *it, int priority, song_handle_
|
||||
song->resource_num = number;
|
||||
song->hold = 0;
|
||||
song->loops = 0;
|
||||
song->wakeup_time = g_system->getMillis(); /* No need to delay */
|
||||
song->_wakeupTime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
|
||||
song_lib_add(self->songlib, song);
|
||||
self->song = NULL; /* As above */
|
||||
_update(self);
|
||||
|
@ -36,8 +36,7 @@ namespace Sci {
|
||||
class SongIterator;
|
||||
struct fade_params_t;
|
||||
|
||||
#define SOUND_TICK 1000 / 60
|
||||
/* Approximately 17 milliseconds */
|
||||
#define SFX_TICKS_PER_SEC 60 /* MIDI ticks per second */
|
||||
|
||||
|
||||
#define SFX_STATE_FLAG_MULTIPLAY (1 << 0) /* More than one song playable
|
||||
|
@ -100,7 +100,7 @@ static void play_song(SongIterator *it, uint32 *wakeup_time, int writeahead_time
|
||||
|
||||
default:
|
||||
play_moredelay = delay - 1;
|
||||
*wakeup_time += delay * SOUND_TICK;
|
||||
*wakeup_time += delay * 1000 / SFX_TICKS_PER_SEC;
|
||||
if (seq->delay)
|
||||
seq->delay(delay);
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ song_t *song_new(song_handle_t handle, SongIterator *it, int priority) {
|
||||
retval->handle = handle;
|
||||
retval->priority = priority;
|
||||
retval->next = NULL;
|
||||
retval->delay = 0;
|
||||
retval->_delay = 0;
|
||||
retval->_wakeupTime = Audio::Timestamp();
|
||||
retval->it = it;
|
||||
retval->status = SOUND_STATUS_STOPPED;
|
||||
retval->next_playing = NULL;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define SCI_SFX_SFX_SONGLIB_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "sound/timestamp.h"
|
||||
|
||||
namespace Sci {
|
||||
|
||||
@ -63,11 +64,9 @@ struct song_t {
|
||||
int hold;
|
||||
|
||||
SongIterator *it;
|
||||
long delay; /* Delay before accessing the iterator, in microseconds */
|
||||
int _delay; /* Delay before accessing the iterator, in ticks */
|
||||
|
||||
uint32 wakeup_time; /* Used by the sound core:
|
||||
** Playing -> time at which 'delay' has elapsed
|
||||
** Suspended/Waiting -> stopping time */
|
||||
Audio::Timestamp _wakeupTime; /**< Timestamp indicating the next MIDI event */
|
||||
|
||||
song_t *next; /* Next song or NULL if this is the last one */
|
||||
song_t *next_playing; /* Next playing song; used by the
|
||||
|
Loading…
Reference in New Issue
Block a user