diff options
author | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 |
---|---|---|
committer | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 |
commit | fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch) | |
tree | ce87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/sfx/player/realtime.c | |
parent | 7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff) | |
download | scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.gz scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.bz2 scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.zip |
Import the SCI engine sources from the FreeSCI Glutton branch (it doesn't compile yet)
svn-id: r38192
Diffstat (limited to 'engines/sci/sfx/player/realtime.c')
-rw-r--r-- | engines/sci/sfx/player/realtime.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/engines/sci/sfx/player/realtime.c b/engines/sci/sfx/player/realtime.c new file mode 100644 index 0000000000..752b0b816b --- /dev/null +++ b/engines/sci/sfx/player/realtime.c @@ -0,0 +1,328 @@ +/*************************************************************************** + realtime.c Copyright (C) 2002..04 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* OK... 'realtime' may be a little too euphemistic, as this one just +** prays for some reasonable amount of soft real-time, but it's close +** enough, I guess. */ + +#include <sfx_player.h> +#include "../sequencer.h" + +static sfx_sequencer_t *seq; + +extern sfx_player_t sfx_player_realtime; + +/* Playing mechanism */ + +static inline GTimeVal +current_time(void) +{ + GTimeVal tv; + sci_get_current_time(&tv); + return tv; +} + +static inline GTimeVal +add_time_delta(GTimeVal tv, long delta) +{ + int sec_d; + + tv.tv_usec += delta; + sec_d = tv.tv_usec / 1000000; + tv.tv_usec -= sec_d * 1000000; + + tv.tv_sec += sec_d; + + return tv; +} + +static inline long +delta_time(GTimeVal comp_tv, GTimeVal base) +{ + GTimeVal tv; + sci_get_current_time(&tv); + return (comp_tv.tv_sec - tv.tv_sec) * 1000000 + + (comp_tv.tv_usec - tv.tv_usec); +} + +static song_iterator_t *play_it = NULL; +static GTimeVal play_last_time; +static GTimeVal play_pause_started; /* Beginning of the last pause */ +static GTimeVal play_pause_counter; /* Last point in time to mark a + ** play position augmentation */ +static int play_paused = 0; +static int play_it_done = 0; +static int play_writeahead = 0; +static int play_moredelay = 0; + +static void +play_song(song_iterator_t *it, GTimeVal *wakeup_time, int writeahead_time) +{ + unsigned char buf[8]; + int result; + + if (play_paused) { + GTimeVal ct; + sci_get_current_time(&ct); + + *wakeup_time = + add_time_delta(*wakeup_time, delta_time(play_pause_counter, ct)); + play_pause_counter = ct; + } else + /* Not paused: */ + while (play_it && delta_time(*wakeup_time, current_time()) + < writeahead_time) { + int delay; + + switch ((delay = songit_next(&(play_it), + &(buf[0]), &result, + IT_READER_MASK_ALL + | IT_READER_MAY_FREE + | IT_READER_MAY_CLEAN))) { + + case SI_FINISHED: + play_it_done = 1; + return; + + case SI_IGNORE: + case SI_LOOP: + case SI_RELATIVE_CUE: + case SI_ABSOLUTE_CUE: + break; + + case SI_PCM: + sfx_play_iterator_pcm(play_it, 0); + break; + + case 0: + seq->event(buf[0], result-1, buf+1); + + break; + + default: + play_moredelay = delay - 1; + *wakeup_time = song_next_wakeup_time(wakeup_time, delay); + if (seq->delay) + seq->delay(delay); + } + } +} + +static void +rt_tell_synth(int buf_nr, byte *buf) +{ + seq->event(buf[0], buf_nr-1, buf+1); +} + +static void +rt_timer_callback(void) +{ + if (play_it && !play_it_done) { + if (!play_moredelay) { + long delta = delta_time(play_last_time, current_time()); + + if (delta < 0) { + play_writeahead -= (int)((double)delta * 1.2); /* Adjust upwards */ + } else if (delta > 15000) { + play_writeahead -= 2500; /* Adjust downwards */ + } + } else --play_moredelay; + + if (play_writeahead < seq->min_write_ahead_ms) + play_writeahead = seq->min_write_ahead_ms; + + play_song(play_it, &play_last_time, play_writeahead); + } +} + +static resource_t * +find_patch(resource_mgr_t *resmgr, const char *seq, int patchfile) +{ + resource_t *res = NULL; + + if (patchfile != SFX_SEQ_PATCHFILE_NONE) { + res = scir_find_resource(resmgr, sci_patch, patchfile, 0); + if (!res) { + fprintf(stderr, "[SFX] " __FILE__": patch.%03d requested by sequencer (%s), but not found\n", + patchfile, seq); + } + } + + return res; +} + +/* API implementation */ + +static int +rt_set_option(char *name, char *value) +{ + return SFX_ERROR; +} + +static int +rt_init(resource_mgr_t *resmgr, int expected_latency) +{ + resource_t *res = NULL, *res2 = NULL; + void *seq_dev = NULL; + GTimeVal foo = {0,0}; + + seq = sfx_find_sequencer(NULL); + + if (!seq) { + fprintf(stderr, "[SFX] " __FILE__": Could not find sequencer\n"); + return SFX_ERROR; + } + + sfx_player_realtime.polyphony = seq->polyphony; + + res = find_patch(resmgr, seq->name, seq->patchfile); + res2 = find_patch(resmgr, seq->name, seq->patchfile2); + + if (seq->device) + seq_dev = sfx_find_device(seq->device, NULL); + + if (seq->open(res? res->size : 0, + res? res->data : NULL, + res2? res2->size : 0, + res2? res2->data : NULL, + seq_dev)) { + fprintf(stderr, "[SFX] " __FILE__": Sequencer failed to initialize\n"); + return SFX_ERROR; + } + + play_writeahead = expected_latency; + if (play_writeahead < seq->min_write_ahead_ms) + play_writeahead = seq->min_write_ahead_ms; + + play_writeahead *= 1000; /* microseconds */ + + if (seq->reset_timer) + seq->reset_timer(foo); + + return SFX_OK; +} + +static int +rt_add_iterator(song_iterator_t *it, GTimeVal start_time) +{ + if (seq->reset_timer) /* Restart timer counting if possible */ + seq->reset_timer(start_time); + + SIMSG_SEND(it, SIMSG_SET_PLAYMASK(seq->playmask)); + SIMSG_SEND(it, SIMSG_SET_RHYTHM(seq->play_rhythm)); + + play_last_time = start_time; + play_it = sfx_iterator_combine(play_it, it); + play_it_done = 0; + play_moredelay = 0; + + return SFX_OK; +} + +static int +rt_fade_out(void) +{ + fprintf(stderr, __FILE__": Attempt to fade out- not implemented yet\n"); + return SFX_ERROR; +} + +static int +rt_stop(void) +{ + song_iterator_t *it = play_it; + + play_it = NULL; + + if (it) + songit_free(it); + if (seq && seq->allstop) + seq->allstop(); + + return SFX_OK; +} + +static int +rt_send_iterator_message(song_iterator_message_t msg) +{ + if (!play_it) + return SFX_ERROR; + + songit_handle_message(&play_it, msg); + return SFX_OK; +} + +static int +rt_pause(void) +{ + sci_get_current_time(&play_pause_started); + /* Also, indicate that we haven't modified the time counter + ** yet */ + play_pause_counter = play_pause_started; + + play_paused = 1; + if (!seq->allstop) { + sciprintf("[SFX] Cannot suspend sequencer, sound will continue for a bit\n"); + return SFX_OK; + } else + return seq->allstop(); +} + +static int +rt_resume(void) +{ + play_paused = 0; + return SFX_OK; +} + +static int +rt_exit(void) +{ + int retval = SFX_OK; + + if(seq->close()) { + fprintf(stderr, "[SFX] Sequencer reported error on close\n"); + retval = SFX_ERROR; + } + + return retval; +} + +sfx_player_t sfx_player_realtime = { + "realtime", + "0.1", + &rt_set_option, + &rt_init, + &rt_add_iterator, + &rt_fade_out, + &rt_stop, + &rt_send_iterator_message, + &rt_pause, + &rt_resume, + &rt_exit, + &rt_timer_callback, + &rt_tell_synth, + 0 /* polyphony */ +}; |