diff options
author | Filippos Karapetis | 2009-11-12 15:24:11 +0000 |
---|---|---|
committer | Filippos Karapetis | 2009-11-12 15:24:11 +0000 |
commit | fbfafb576e14bdd31d69eb1b6a262bb8d667e852 (patch) | |
tree | 0a31b65e91f3c444cb821e504726f651053a9b6d /engines/sci | |
parent | 3d796d6c088677ab30f1aae0226651f46d46013f (diff) | |
download | scummvm-rg350-fbfafb576e14bdd31d69eb1b6a262bb8d667e852.tar.gz scummvm-rg350-fbfafb576e14bdd31d69eb1b6a262bb8d667e852.tar.bz2 scummvm-rg350-fbfafb576e14bdd31d69eb1b6a262bb8d667e852.zip |
Started objectifying kDoSound()
svn-id: r45862
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/engine/ksound.cpp | 964 | ||||
-rw-r--r-- | engines/sci/engine/savegame.cpp | 7 | ||||
-rw-r--r-- | engines/sci/engine/state.cpp | 2 | ||||
-rw-r--r-- | engines/sci/engine/state.h | 3 | ||||
-rw-r--r-- | engines/sci/module.mk | 1 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 5 | ||||
-rw-r--r-- | engines/sci/sfx/soundcmd.cpp | 567 | ||||
-rw-r--r-- | engines/sci/sfx/soundcmd.h | 91 |
8 files changed, 674 insertions, 966 deletions
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 9e38799156..31aeb981d0 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -27,6 +27,7 @@ #include "sci/engine/state.h" #include "sci/sfx/iterator.h" #include "sci/sfx/misc.h" +#include "sci/sfx/soundcmd.h" #include "sci/engine/kernel.h" #include "sci/engine/vm.h" // for Object @@ -34,972 +35,11 @@ namespace Sci { -/* Sound status */ -enum { - _K_SOUND_STATUS_STOPPED = 0, - _K_SOUND_STATUS_INITIALIZED = 1, - _K_SOUND_STATUS_PAUSED = 2, - _K_SOUND_STATUS_PLAYING = 3 -}; - -enum { - _K_SCI0_SOUND_INIT_HANDLE = 0, - _K_SCI0_SOUND_PLAY_HANDLE = 1, - _K_SCI0_SOUND_NOP = 2, - _K_SCI0_SOUND_DISPOSE_HANDLE = 3, - _K_SCI0_SOUND_MUTE_SOUND = 4, - _K_SCI0_SOUND_STOP_HANDLE = 5, - _K_SCI0_SOUND_SUSPEND_HANDLE = 6, - _K_SCI0_SOUND_RESUME_HANDLE = 7, - _K_SCI0_SOUND_VOLUME = 8, - _K_SCI0_SOUND_UPDATE_VOL_PRI = 9, - _K_SCI0_SOUND_FADE_HANDLE = 10, - _K_SCI0_SOUND_GET_POLYPHONY = 11, - _K_SCI0_SOUND_PLAY_NEXT = 12 -}; - -enum { - _K_SCI01_SOUND_MASTER_VOLME = 0, /* Set/Get */ - _K_SCI01_SOUND_MUTE_SOUND = 1, - _K_SCI01_SOUND_UNUSED = 2, - _K_SCI01_SOUND_GET_POLYPHONY = 3, - _K_SCI01_SOUND_UPDATE_HANDLE = 4, - _K_SCI01_SOUND_INIT_HANDLE = 5, - _K_SCI01_SOUND_DISPOSE_HANDLE = 6, - _K_SCI01_SOUND_PLAY_HANDLE = 7, - _K_SCI01_SOUND_STOP_HANDLE = 8, - _K_SCI01_SOUND_SUSPEND_HANDLE = 9, /* or resume */ - _K_SCI01_SOUND_FADE_HANDLE = 10, - _K_SCI01_SOUND_UPDATE_CUES = 11, - _K_SCI01_SOUND_MIDI_SEND = 12, - _K_SCI01_SOUND_REVERB = 13, /* Get/Set */ - _K_SCI01_SOUND_HOLD = 14 -}; - -enum { - _K_SCI1_SOUND_MASTER_VOLME = 0, /* Set/Get */ - _K_SCI1_SOUND_MUTE_SOUND = 1, - _K_SCI1_SOUND_UNUSED1 = 2, - _K_SCI1_SOUND_GET_POLYPHONY = 3, - _K_SCI1_SOUND_GET_AUDIO_CAPABILITY = 4, - _K_SCI1_SOUND_SUSPEND_SOUND = 5, - _K_SCI1_SOUND_INIT_HANDLE = 6, - _K_SCI1_SOUND_DISPOSE_HANDLE = 7, - _K_SCI1_SOUND_PLAY_HANDLE = 8, - _K_SCI1_SOUND_STOP_HANDLE = 9, - _K_SCI1_SOUND_SUSPEND_HANDLE = 10, /* or resume */ - _K_SCI1_SOUND_FADE_HANDLE = 11, - _K_SCI1_SOUND_HOLD_HANDLE = 12, - _K_SCI1_SOUND_UNUSED2 = 13, - _K_SCI1_SOUND_SET_HANDLE_VOLUME = 14, - _K_SCI1_SOUND_SET_HANDLE_PRIORITY = 15, - _K_SCI1_SOUND_SET_HANDLE_LOOP = 16, - _K_SCI1_SOUND_UPDATE_CUES = 17, - _K_SCI1_SOUND_MIDI_SEND = 18, - _K_SCI1_SOUND_REVERB = 19, /* Get/Set */ - _K_SCI1_SOUND_UPDATE_VOL_PRI = 20 -}; - -#define SCI1_SOUND_FLAG_MAY_PAUSE 1 /* Only here for completeness; The interpreter doesn't touch this bit */ -#define SCI1_SOUND_FLAG_SCRIPTED_PRI 2 /* but does touch this */ -//#define DEBUG_SOUND // enable for sound debugging - -#define FROBNICATE_HANDLE(reg) ((reg).segment << 16 | (reg).offset) -#define DEFROBNICATE_HANDLE(handle) (make_reg((handle >> 16) & 0xffff, handle & 0xffff)) - - -static void script_set_priority(EngineState *s, reg_t obj, int priority) { - SegManager *segMan = s->_segMan; - int song_nr = GET_SEL32V(segMan, obj, number); - Resource *song = s->resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0); - int flags = GET_SEL32V(segMan, obj, flags); - - if (priority == -1) { - if (song->data[0] == 0xf0) - priority = song->data[1]; - else - warning("Attempt to unset song priority when there is no built-in value"); - - flags &= ~SCI1_SOUND_FLAG_SCRIPTED_PRI; - } else flags |= SCI1_SOUND_FLAG_SCRIPTED_PRI; - - s->_sound.sfx_song_renice(FROBNICATE_HANDLE(obj), priority); - PUT_SEL32V(segMan, obj, flags, flags); -} - -SongIterator *build_iterator(EngineState *s, int song_nr, SongIteratorType type, songit_id_t id) { - Resource *song = s->resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0); - - if (!song) - return NULL; - - return songit_new(song->data, song->size, type, id); -} - -SongIterator *build_timeriterator(EngineState *s, int delta) { - return new_timer_iterator(delta); -} - -void process_sound_events(EngineState *s) { /* Get all sound events, apply their changes to the heap */ - int result; - SongHandle handle; - int cue; - SegManager *segMan = s->_segMan; - - if (getSciVersion() > SCI_VERSION_01) - return; - /* SCI1 and later explicitly poll for everything */ - - while ((result = s->_sound.sfx_poll(&handle, &cue))) { - reg_t obj = DEFROBNICATE_HANDLE(handle); - if (!s->_segMan->isObject(obj)) { - warning("Non-object %04x:%04x received sound signal (%d/%d)", PRINT_REG(obj), result, cue); - return; - } - - switch (result) { - - case SI_LOOP: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x looped (to %d)\n", - PRINT_REG(obj), cue); - /* PUT_SEL32V(segMan, obj, loops, GET_SEL32V(segMan, obj, loop) - 1);*/ - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - break; - - case SI_RELATIVE_CUE: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d\n", - PRINT_REG(obj), cue); - PUT_SEL32V(segMan, obj, signal, cue + 0x7f); - break; - - case SI_ABSOLUTE_CUE: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d\n", - PRINT_REG(obj), cue); - PUT_SEL32V(segMan, obj, signal, cue); - break; - - case SI_FINISHED: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished\n", - PRINT_REG(obj)); - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - PUT_SEL32V(segMan, obj, state, _K_SOUND_STATUS_STOPPED); - break; - - default: - warning("Unexpected result from sfx_poll: %d", result); - break; - } - } -} - - -static reg_t kDoSoundSci0(EngineState *s, int argc, reg_t *argv) { - SegManager *segMan = s->_segMan; - reg_t obj = (argc > 1) ? argv[1] : NULL_REG; - uint16 command = argv[0].toUint16(); - SongHandle handle = FROBNICATE_HANDLE(obj); - int number = obj.segment ? - GET_SEL32V(segMan, obj, number) : - -1; /* We were not going to use it anyway */ - -#ifdef DEBUG_SOUND - int i; - - debugC(2, kDebugLevelSound, "Command 0x%x", command); - switch (command) { - case 0: - debugC(2, kDebugLevelSound, "[InitObj]"); - break; - case 1: - debugC(2, kDebugLevelSound, "[Play]"); - break; - case 2: - debugC(2, kDebugLevelSound, "[NOP]"); - break; - case 3: - debugC(2, kDebugLevelSound, "[DisposeHandle]"); - break; - case 4: - debugC(2, kDebugLevelSound, "[SetSoundOn(?)]"); - break; - case 5: - debugC(2, kDebugLevelSound, "[Stop]"); - break; - case 6: - debugC(2, kDebugLevelSound, "[Suspend]"); - break; - case 7: - debugC(2, kDebugLevelSound, "[Resume]"); - break; - case 8: - debugC(2, kDebugLevelSound, "[Get(Set?)Volume]"); - break; - case 9: - debugC(2, kDebugLevelSound, "[Signal: Obj changed]"); - break; - case 10: - debugC(2, kDebugLevelSound, "[Fade(?)]"); - break; - case 11: - debugC(2, kDebugLevelSound, "[ChkDriver]"); - break; - case 12: - debugC(2, kDebugLevelSound, "[PlayNextSong (formerly StopAll)]"); - break; - default: - debugC(2, kDebugLevelSound, "[unknown]"); - break; - } - - debugC(2, kDebugLevelSound, "("); - for (i = 1; i < argc; i++) { - debugC(2, kDebugLevelSound, "%04x:%04x", PRINT_REG(argv[i])); - if (i + 1 < argc) - debugC(2, kDebugLevelSound, ", "); - } - debugC(2, kDebugLevelSound, ")\n"); -#endif // DEBUG_SOUND - - - switch (command) { - case _K_SCI0_SOUND_INIT_HANDLE: - if (obj.segment) { - debugC(2, kDebugLevelSound, "Initializing song number %d\n", GET_SEL32V(segMan, obj, number)); - s->_sound.sfx_add_song(build_iterator(s, number, SCI_SONG_ITERATOR_TYPE_SCI0, - handle), 0, handle, number); - - PUT_SEL32V(segMan, obj, state, _K_SOUND_STATUS_INITIALIZED); - PUT_SEL32(segMan, obj, handle, obj); /* ``sound handle'': we use the object address */ - } - break; - - case _K_SCI0_SOUND_PLAY_HANDLE: - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_PLAYING); - s->_sound.sfx_song_set_loops(handle, GET_SEL32V(segMan, obj, loop)); - PUT_SEL32V(segMan, obj, state, _K_SOUND_STATUS_PLAYING); - } - break; - - case _K_SCI0_SOUND_NOP: - break; - - case _K_SCI0_SOUND_DISPOSE_HANDLE: - if (obj.segment) { - s->_sound.sfx_remove_song(handle); - } - PUT_SEL32V(segMan, obj, handle, 0x0000); - break; - - case _K_SCI0_SOUND_STOP_HANDLE: - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - PUT_SEL32V(segMan, obj, state, SOUND_STATUS_STOPPED); - } - break; - - case _K_SCI0_SOUND_SUSPEND_HANDLE: - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_SUSPENDED); - PUT_SEL32V(segMan, obj, state, SOUND_STATUS_SUSPENDED); - } - break; - - case _K_SCI0_SOUND_RESUME_HANDLE: - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_PLAYING); - PUT_SEL32V(segMan, obj, state, SOUND_STATUS_PLAYING); - } - break; - - case _K_SCI0_SOUND_MUTE_SOUND: { - /* if there's a parameter, we're setting it. Otherwise, - we're querying it. */ - /*int param = UPARAM_OR_ALT(1,-1); - - if (param != -1) - s->acc = s->sound_server->command(s, SOUND_COMMAND_SET_MUTE, 0, param); - else - s->acc = s->sound_server->command(s, SOUND_COMMAND_GET_MUTE, 0, 0);*/ - - } - break; - - case _K_SCI0_SOUND_VOLUME: { - /* range from 0x0 to 0xf */ - /* parameter optional. If present, set.*/ - int vol = (argc > 1) ? argv[1].toSint16() : -1; - - if (vol != -1) - s->_sound.sfx_setVolume(vol); - else - s->r_acc = make_reg(0, s->_sound.sfx_getVolume()); - } - break; - - case _K_SCI0_SOUND_UPDATE_VOL_PRI: - if (obj.segment) { - s->_sound.sfx_song_set_loops(handle, GET_SEL32V(segMan, obj, loop)); - script_set_priority(s, obj, GET_SEL32V(segMan, obj, pri)); - } - break; - - case _K_SCI0_SOUND_FADE_HANDLE: - /*s->sound_server->command(s, SOUND_COMMAND_FADE_HANDLE, obj, 120);*/ /* Fade out in 2 secs */ - /* FIXME: The next couple of lines actually STOP the handle, rather - ** than fading it! */ - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - PUT_SEL32V(segMan, obj, state, SOUND_STATUS_STOPPED); - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - } - break; - - case _K_SCI0_SOUND_GET_POLYPHONY: - s->r_acc = make_reg(0, s->_sound.sfx_get_player_polyphony()); - break; - - case _K_SCI0_SOUND_PLAY_NEXT: - /* s->_sound.sfx_all_stop();*/ - break; - - default: - warning("Unhandled DoSound command: %x", command); - - } - // process_sound_events(s); /* Take care of incoming events */ - - return s->r_acc; -} - - -static reg_t kDoSoundSci1Early(EngineState *s, int argc, reg_t *argv) { - SegManager *segMan = s->_segMan; - uint16 command = argv[0].toUint16(); - reg_t obj = (argc > 1) ? argv[1] : NULL_REG; - SongHandle handle = FROBNICATE_HANDLE(obj); - int number = obj.segment ? - GET_SEL32V(segMan, obj, number) : - -1; /* We were not going to use it anyway */ - -#ifdef DEBUG_SOUND - if (command != _K_SCI01_SOUND_UPDATE_CUES) { - int i; - - debugC(2, kDebugLevelSound, "Command 0x%x", command); - switch (command) { - case 0: - debugC(2, kDebugLevelSound, "[MasterVolume]"); - break; - case 1: - debugC(2, kDebugLevelSound, "[Mute]"); - break; - case 2: - debugC(2, kDebugLevelSound, "[NOP(2)]"); - break; - case 3: - debugC(2, kDebugLevelSound, "[GetPolyphony]"); - break; - case 4: - debugC(2, kDebugLevelSound, "[Update]"); - break; - case 5: - debugC(2, kDebugLevelSound, "[Init]"); - break; - case 6: - debugC(2, kDebugLevelSound, "[Dispose]"); - break; - case 7: - debugC(2, kDebugLevelSound, "[Play]"); - break; - case 8: - debugC(2, kDebugLevelSound, "[Stop]"); - break; - case 9: - debugC(2, kDebugLevelSound, "[Suspend]"); - break; - case 10: - debugC(2, kDebugLevelSound, "[Fade]"); - break; - case 11: - debugC(2, kDebugLevelSound, "[UpdateCues]"); - break; - case 12: - debugC(2, kDebugLevelSound, "[MidiSend]"); - break; - case 13: - debugC(2, kDebugLevelSound, "[Reverb]"); - break; - case 14: - debugC(2, kDebugLevelSound, "[Hold]"); - break; - default: - debugC(2, kDebugLevelSound, "[unknown]"); - break; - } - - debugC(2, kDebugLevelSound, "("); - for (i = 1; i < argc; i++) { - debugC(2, kDebugLevelSound, "%04x:%04x", PRINT_REG(argv[i])); - if (i + 1 < argc) - debugC(2, kDebugLevelSound, ", "); - } - debugC(2, kDebugLevelSound, ")\n"); - } -#endif - - switch (command) { - case _K_SCI01_SOUND_MASTER_VOLME : { - int vol = (argc > 1) ? argv[1].toSint16() : -1; - - if (vol != -1) - s->_sound.sfx_setVolume(vol); - else - s->r_acc = make_reg(0, s->_sound.sfx_getVolume()); - break; - } - case _K_SCI01_SOUND_MUTE_SOUND : { - /* if there's a parameter, we're setting it. Otherwise, - we're querying it. */ - /*int param = UPARAM_OR_ALT(1,-1); - - if (param != -1) - s->acc = s->sound_server->command(s, SOUND_COMMAND_SET_MUTE, 0, param); - else - s->acc = s->sound_server->command(s, SOUND_COMMAND_GET_MUTE, 0, 0);*/ - - break; - } - case _K_SCI01_SOUND_UNUSED : { - break; - } - case _K_SCI01_SOUND_GET_POLYPHONY : { - s->r_acc = make_reg(0, s->_sound.sfx_get_player_polyphony()); - break; - } - case _K_SCI01_SOUND_PLAY_HANDLE : { - int looping = GET_SEL32V(segMan, obj, loop); - //int vol = GET_SEL32V(segMan, obj, vol); - int pri = GET_SEL32V(segMan, obj, pri); - RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) argv[2].toUint16(); /* Too lazy to look up a default value for this */ - - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_PLAYING); - s->_sound.sfx_song_set_loops(handle, looping); - s->_sound.sfx_song_renice(handle, pri); - s->_sound._songlib.setSongRestoreBehavior(handle, rb); - PUT_SEL32V(segMan, obj, signal, 0); - } - - break; - } - case _K_SCI01_SOUND_INIT_HANDLE : { - //int looping = GET_SEL32V(segMan, obj, loop); - //int vol = GET_SEL32V(segMan, obj, vol); - //int pri = GET_SEL32V(segMan, obj, pri); - - if (obj.segment && (s->resMan->testResource(ResourceId(kResourceTypeSound, number)))) { - debugC(2, kDebugLevelSound, "Initializing song number %d\n", number); - s->_sound.sfx_add_song(build_iterator(s, number, SCI_SONG_ITERATOR_TYPE_SCI1, - handle), 0, handle, number); - PUT_SEL32(segMan, obj, nodePtr, obj); - PUT_SEL32(segMan, obj, handle, obj); - } - break; - } - case _K_SCI01_SOUND_DISPOSE_HANDLE : { - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - s->_sound.sfx_remove_song(handle); - } - break; - } - case _K_SCI01_SOUND_UPDATE_HANDLE : { - /* FIXME: Get these from the sound server */ - int signal = 0; - int min = 0; - int sec = 0; - int frame = 0; - - /* FIXME: Update the sound server state with 'vol' */ - int looping = GET_SEL32V(segMan, obj, loop); - //int vol = GET_SEL32V(segMan, obj, vol); - int pri = GET_SEL32V(segMan, obj, pri); - - s->_sound.sfx_song_set_loops(handle, looping); - s->_sound.sfx_song_renice(handle, pri); - - debugC(2, kDebugLevelSound, "[sound01-update-handle] -- CUE %04x:%04x", PRINT_REG(obj)); - - PUT_SEL32V(segMan, obj, signal, signal); - PUT_SEL32V(segMan, obj, min, min); - PUT_SEL32V(segMan, obj, sec, sec); - PUT_SEL32V(segMan, obj, frame, frame); - - break; - } - case _K_SCI01_SOUND_STOP_HANDLE : { - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - } - break; - } - case _K_SCI01_SOUND_SUSPEND_HANDLE : { - int state = argv[2].toUint16(); - int setstate = (state) ? - SOUND_STATUS_SUSPENDED : SOUND_STATUS_PLAYING; - - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, setstate); - } - break; - } - case _K_SCI01_SOUND_FADE_HANDLE : { - /* There are four parameters that control the fade here. - * TODO: Figure out the exact semantics */ - - /* FIXME: The next couple of lines actually STOP the song right away */ - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - } - break; - } - case _K_SCI01_SOUND_UPDATE_CUES : { - int signal = 0; - int min = 0; - int sec = 0; - int frame = 0; - int result = SI_LOOP; /* small hack */ - int cue = 0; - - while (result == SI_LOOP) - result = s->_sound.sfx_poll_specific(handle, &cue); - - switch (result) { - - case SI_ABSOLUTE_CUE: - signal = cue; - debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Absolute Cue: %d\n", - PRINT_REG(obj), signal); - - PUT_SEL32V(segMan, obj, signal, signal); - break; - - case SI_RELATIVE_CUE: - signal = cue; - debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Relative Cue: %d\n", - PRINT_REG(obj), cue); - - /* FIXME to match commented-out semantics - * below, with proper storage of dataInc and - * signal in the iterator code. */ - PUT_SEL32V(segMan, obj, dataInc, signal); - PUT_SEL32V(segMan, obj, signal, signal); - break; - - case SI_FINISHED: - debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x\n", PRINT_REG(obj)); - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - break; - - case SI_LOOP: - break; /* Doesn't happen */ - } - - /* switch (signal) */ - /* { */ - /* case 0x00: */ - /* if (dataInc!=GET_SEL32V(segMan, obj, dataInc)) */ - /* { */ - /* PUT_SEL32V(segMan, obj, dataInc, dataInc); */ - /* PUT_SEL32V(segMan, obj, signal, dataInc+0x7f); */ - /* } else */ - /* { */ - /* PUT_SEL32V(segMan, obj, signal, signal); */ - /* } */ - /* break; */ - /* case 0xFF: /\* May be unnecessary *\/ */ - /* s->_sound.sfx_song_set_status(*/ - /* handle, SOUND_STATUS_STOPPED); */ - /* break; */ - /* default : */ - /* if (dataInc!=GET_SEL32V(segMan, obj, dataInc)) */ - /* { */ - /* PUT_SEL32V(segMan, obj, dataInc, dataInc); */ - /* PUT_SEL32V(segMan, obj, signal, dataInc+0x7f); */ - /* } else */ - /* { */ - /* PUT_SEL32V(segMan, obj, signal, signal); */ - /* } */ - /* break; */ - /* } */ - - PUT_SEL32V(segMan, obj, min, min); - PUT_SEL32V(segMan, obj, sec, sec); - PUT_SEL32V(segMan, obj, frame, frame); - break; - } - case _K_SCI01_SOUND_MIDI_SEND : { - int channel = argv[2].toSint16(); - int midiCmd = argv[3].toUint16() == 0xff ? - 0xe0 : /* Pitch wheel */ - 0xb0; /* argv[3].toUint16() is actually a controller number */ - int controller = argv[3].toUint16(); - int param = argv[4].toUint16(); - - s->_sound.sfx_send_midi(handle, - channel, midiCmd, controller, param); - break; - } - case _K_SCI01_SOUND_REVERB : { - break; - } - case _K_SCI01_SOUND_HOLD : { - //int flag = argv[2].toSint16(); - break; - } - } - - return s->r_acc; -} - -static reg_t kDoSoundSci1Late(EngineState *s, int argc, reg_t *argv) { - SegManager *segMan = s->_segMan; - uint16 command = argv[0].toUint16(); - reg_t obj = (argc > 1) ? argv[1] : NULL_REG; - SongHandle handle = FROBNICATE_HANDLE(obj); - int number = obj.segment ? - GET_SEL32V(segMan, obj, number) : - -1; /* We were not going to use it anyway */ - -#ifdef DEBUG_SOUND - if (command != _K_SCI1_SOUND_UPDATE_CUES) { - int i; - - debugC(2, kDebugLevelSound, "Command 0x%x", command); - switch (command) { - case 0: - debugC(2, kDebugLevelSound, "[MasterVolume]"); - break; - case 1: - debugC(2, kDebugLevelSound, "[Mute]"); - break; - case 2: - debugC(2, kDebugLevelSound, "[NOP(2)]"); - break; - case 3: - debugC(2, kDebugLevelSound, "[GetPolyphony]"); - break; - case 4: - debugC(2, kDebugLevelSound, "[GetAudioCapability]"); - break; - case 5: - debugC(2, kDebugLevelSound, "[GlobalSuspend]"); - break; - case 6: - debugC(2, kDebugLevelSound, "[Init]"); - break; - case 7: - debugC(2, kDebugLevelSound, "[Dispose]"); - break; - case 8: - debugC(2, kDebugLevelSound, "[Play]"); - break; - case 9: - debugC(2, kDebugLevelSound, "[Stop]"); - break; - case 10: - debugC(2, kDebugLevelSound, "[SuspendHandle]"); - break; - case 11: - debugC(2, kDebugLevelSound, "[Fade]"); - break; - case 12: - debugC(2, kDebugLevelSound, "[Hold]"); - break; - case 13: - debugC(2, kDebugLevelSound, "[Unused(13)]"); - break; - case 14: - debugC(2, kDebugLevelSound, "[SetVolume]"); - break; - case 15: - debugC(2, kDebugLevelSound, "[SetPriority]"); - break; - case 16: - debugC(2, kDebugLevelSound, "[SetLoop]"); - break; - case 17: - debugC(2, kDebugLevelSound, "[UpdateCues]"); - break; - case 18: - debugC(2, kDebugLevelSound, "[MidiSend]"); - break; - case 19: - debugC(2, kDebugLevelSound, "[Reverb]"); - break; - case 20: - debugC(2, kDebugLevelSound, "[UpdateVolPri]"); - break; - default: - debugC(2, kDebugLevelSound, "[unknown]"); - break; - } - - debugC(2, kDebugLevelSound, "("); - for (i = 1; i < argc; i++) { - debugC(2, kDebugLevelSound, "%04x:%04x", PRINT_REG(argv[i])); - if (i + 1 < argc) - debugC(2, kDebugLevelSound, ", "); - } - debugC(2, kDebugLevelSound, ")\n"); - } -#endif // DEBUG_SOUND - - switch (command) { - case _K_SCI1_SOUND_MASTER_VOLME : { - int vol = (argc > 1 ? argv[1].offset : -1); - - if (vol != -1) - s->_sound.sfx_setVolume(vol); - - s->r_acc = make_reg(0, s->_sound.sfx_getVolume()); - break; - } - case _K_SCI1_SOUND_MUTE_SOUND : { - /* if there's a parameter, we're setting it. Otherwise, - we're querying it. */ - /*int param = UPARAM_OR_ALT(1,-1); - - if (param != -1) - s->acc = s->sound_server->command(s, SOUND_COMMAND_SET_MUTE, 0, param); - else - s->acc = s->sound_server->command(s, SOUND_COMMAND_GET_MUTE, 0, 0); - break;*/ - } - case _K_SCI1_SOUND_UNUSED1 : { - break; - } - case _K_SCI1_SOUND_GET_POLYPHONY : { - /*s->acc = s->sound_server->command(s, SOUND_COMMAND_TEST, 0, 0);*/ - break; - } - case _K_SCI1_SOUND_GET_AUDIO_CAPABILITY : { - // Tests for digital audio support - return make_reg(0, 1); - } - case _K_SCI1_SOUND_PLAY_HANDLE : { - int looping = GET_SEL32V(segMan, obj, loop); - //int vol = GET_SEL32V(segMan, obj, vol); - int pri = GET_SEL32V(segMan, obj, pri); - int sampleLen = 0; - Song *song = s->_sound._songlib.findSong(handle); - - if (GET_SEL32V(segMan, obj, nodePtr) && (song && number != song->_resourceNum)) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - s->_sound.sfx_remove_song(handle); - PUT_SEL32(segMan, obj, nodePtr, NULL_REG); - } - - if (!GET_SEL32V(segMan, obj, nodePtr) && obj.segment) { - // In SCI1.1 games, sound effects are started from here. If we can find - // a relevant audio resource, play it, otherwise switch to synthesized - // effects. If the resource exists, play it using map 65535 (sound - // effects map) - if (s->resMan->testResource(ResourceId(kResourceTypeAudio, number)) && - getSciVersion() >= SCI_VERSION_1_1) { - // Found a relevant audio resource, play it - s->_audio->stopAudio(); - warning("Initializing audio resource instead of requested sound resource %d", number); - sampleLen = s->_audio->startAudio(65535, number); - // Also create iterator, that will fire SI_FINISHED event, when the sound is done playing - s->_sound.sfx_add_song(build_timeriterator(s, sampleLen), 0, handle, number); - } else { - if (!s->resMan->testResource(ResourceId(kResourceTypeSound, number))) { - warning("Could not open song number %d", number); - // Send a "stop handle" event so that the engine won't wait forever here - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - return s->r_acc; - } - debugC(2, kDebugLevelSound, "Initializing song number %d\n", number); - s->_sound.sfx_add_song(build_iterator(s, number, SCI_SONG_ITERATOR_TYPE_SCI1, - handle), 0, handle, number); - } - - PUT_SEL32(segMan, obj, nodePtr, obj); - PUT_SEL32(segMan, obj, handle, obj); - } - - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_PLAYING); - s->_sound.sfx_song_set_loops(handle, looping); - s->_sound.sfx_song_renice(handle, pri); - PUT_SEL32V(segMan, obj, signal, 0); - } - - break; - } - case _K_SCI1_SOUND_INIT_HANDLE : { - //int looping = GET_SEL32V(segMan, obj, loop); - //int vol = GET_SEL32V(segMan, obj, vol); - //int pri = GET_SEL32V(segMan, obj, pri); - - if (GET_SEL32V(segMan, obj, nodePtr)) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - s->_sound.sfx_remove_song(handle); - } - - if (obj.segment && (s->resMan->testResource(ResourceId(kResourceTypeSound, number)))) { - debugC(2, kDebugLevelSound, "Initializing song number %d\n", number); - s->_sound.sfx_add_song(build_iterator(s, number, SCI_SONG_ITERATOR_TYPE_SCI1, - handle), 0, handle, number); - PUT_SEL32(segMan, obj, nodePtr, obj); - PUT_SEL32(segMan, obj, handle, obj); - } - break; - } - case _K_SCI1_SOUND_DISPOSE_HANDLE : { - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - s->_sound.sfx_remove_song(handle); - } - break; - } - case _K_SCI1_SOUND_STOP_HANDLE : { - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - if (obj.segment) { - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - } - break; - } - case _K_SCI1_SOUND_SUSPEND_HANDLE : { - break; - } - case _K_SCI1_SOUND_FADE_HANDLE : { - fade_params_t fade; - if (obj.segment) { - fade.final_volume = argv[2].toUint16(); - fade.ticks_per_step = argv[3].toUint16(); - fade.step_size = argv[4].toUint16(); - fade.action = argv[5].toUint16() ? - FADE_ACTION_FADE_AND_STOP : - FADE_ACTION_FADE_AND_CONT; - - s->_sound.sfx_song_set_fade(handle, &fade); - - /* FIXME: The next couple of lines actually STOP the handle, rather - ** than fading it! */ - if (argv[5].toUint16()) { - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - } else { - // FIXME: Support fade-and-continue. For now, send signal right away. - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - } - } - break; - } - case _K_SCI1_SOUND_HOLD_HANDLE : { - int value = argv[2].toSint16(); - - s->_sound.sfx_song_set_hold(handle, value); - break; - } - case _K_SCI1_SOUND_UNUSED2 : { - break; - } - case _K_SCI1_SOUND_SET_HANDLE_VOLUME : { - break; - } - case _K_SCI1_SOUND_SET_HANDLE_PRIORITY : { - int value = argv[2].toSint16(); - - script_set_priority(s, obj, value); - break; - } - case _K_SCI1_SOUND_SET_HANDLE_LOOP : { - if (!GET_SEL32(segMan, obj, nodePtr).isNull()) { - uint16 looping = argv[2].toUint16(); - - if (looping < 65535) - looping = 1; - - s->_sound.sfx_song_set_loops(handle, looping); - PUT_SEL32V(segMan, obj, loop, looping); - } - break; - } - case _K_SCI1_SOUND_UPDATE_CUES : { - int signal = 0; - //int min = 0; - //int sec = 0; - //int frame = 0; - int result = SI_LOOP; /* small hack */ - int cue = 0; - - while (result == SI_LOOP) - result = s->_sound.sfx_poll_specific(handle, &cue); - - switch (result) { - - case SI_ABSOLUTE_CUE: - signal = cue; - debugC(2, kDebugLevelSound, "[CUE] %04x:%04x Absolute Cue: %d\n", - PRINT_REG(obj), signal); - - PUT_SEL32V(segMan, obj, signal, signal); - break; - - case SI_RELATIVE_CUE: - debugC(2, kDebugLevelSound, "[CUE] %04x:%04x Relative Cue: %d\n", - PRINT_REG(obj), cue); - - PUT_SEL32V(segMan, obj, dataInc, cue); - PUT_SEL32V(segMan, obj, signal, cue + 127); - break; - - case SI_FINISHED: - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - break; - - case SI_LOOP: - break; /* Doesn't happen */ - } - break; - } - case _K_SCI1_SOUND_MIDI_SEND : { - s->_sound.sfx_send_midi(handle, - argv[2].toUint16(), argv[3].toUint16(), argv[4].toUint16(), argv[5].toUint16()); - break; - } - case _K_SCI1_SOUND_REVERB : { - break; - } - case _K_SCI1_SOUND_UPDATE_VOL_PRI : { - break; - } - } - return s->r_acc; -} - /** * Used for synthesized music playback */ reg_t kDoSound(EngineState *s, int argc, reg_t *argv) { - switch (s->detectDoSoundType()) { - case SCI_VERSION_0_EARLY: - return kDoSoundSci0(s, argc, argv); - case SCI_VERSION_1_EARLY: - return kDoSoundSci1Early(s, argc, argv); - case SCI_VERSION_1_LATE: - return kDoSoundSci1Late(s, argc, argv); - default: - warning("Unknown DoSound type"); - return NULL_REG; - } + return s->_soundCmd->parseCommand(argc, argv, s->r_acc); } reg_t kDoCdAudio(EngineState *s, int argc, reg_t *argv) { diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 046d4194d9..03b31b39c7 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -55,8 +55,7 @@ const uint32 INTMAPPER_MAGIC_KEY = 0xDEADBEEF; // from ksound.cpp: -//SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id); -SongIterator *build_iterator(EngineState *s, int song_nr, SongIteratorType type, songit_id_t id); +SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id); #pragma mark - @@ -708,8 +707,7 @@ static void reconstruct_sounds(EngineState *s) { int oldstatus; SongIterator::Message msg; - //base = ff = build_iterator(s->resMan, seeker->_resourceNum, it_type, seeker->_handle); - base = ff = build_iterator(s, seeker->_resourceNum, it_type, seeker->_handle); + base = ff = build_iterator(s->resMan, seeker->_resourceNum, it_type, seeker->_handle); if (seeker->_restoreBehavior == RESTORE_BEHAVIOR_CONTINUE) ff = new_fast_forward_iterator(base, seeker->_restoreTime); ff->init(); @@ -772,6 +770,7 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { // Copy some old data retval->gfx_state = s->gfx_state; + retval->_soundCmd = s->_soundCmd; retval->saveLoadWithSerializer(ser); // FIXME: Error handling? diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 5f325cd794..9245d7c1df 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -108,6 +108,8 @@ EngineState::EngineState(ResourceManager *res, Kernel *kernel, Vocabulary *voc, _moveCountType = kMoveCountUninitialized; _usesCdTrack = Common::File::exists("cdaudio.map"); + + _soundCmd = 0; } EngineState::~EngineState() { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index e2368a505d..7332eae61c 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -44,6 +44,7 @@ namespace Common { #include "sci/gfx/gfx_system.h" #include "sci/sfx/audio.h" #include "sci/sfx/core.h" +#include "sci/sfx/soundcmd.h" namespace Sci { @@ -51,6 +52,7 @@ class Menubar; class SciGui; class SciGuiCursor; class MessageState; +class SoundCommandParser; struct GfxState; struct GfxPort; @@ -137,6 +139,7 @@ public: AudioPlayer *_audio; SfxState _sound; /**< sound subsystem */ + SoundCommandParser *_soundCmd; int sfx_init_flags; /**< flags the sfx subsystem was initialised with */ byte restarting_flags; /**< Flags used for restarting */ diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 649faea14a..baca55f6eb 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -71,6 +71,7 @@ MODULE_OBJS := \ sfx/core.o \ sfx/iterator.o \ sfx/songlib.o \ + sfx/soundcmd.o \ sfx/seq/gm.o \ sfx/seq/instrument-map.o \ sfx/seq/map-mt32-to-gm.o \ diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 5f859b7310..a675f5bff4 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -41,6 +41,7 @@ #include "sci/gui32/gui32.h" #endif #include "sci/sfx/audio.h" +#include "sci/sfx/soundcmd.h" #include "sci/gui/gui.h" #include "sci/gui/gui_palette.h" #include "sci/gui/gui_cursor.h" @@ -161,6 +162,8 @@ Common::Error SciEngine::run() { // since we cannot let the game control where saves are stored) strcpy(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value, "/"); + _gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, &_gamestate->_sound, _audio, _gamestate->detectDoSoundType()); + GfxState gfx_state; _gamestate->gfx_state = &gfx_state; @@ -191,6 +194,8 @@ Common::Error SciEngine::run() { game_exit(_gamestate); script_free_breakpoints(_gamestate); + delete _gamestate->_soundCmd; + delete _gamestate->_gui; delete segMan; delete cursor; delete palette; diff --git a/engines/sci/sfx/soundcmd.cpp b/engines/sci/sfx/soundcmd.cpp new file mode 100644 index 0000000000..c984909497 --- /dev/null +++ b/engines/sci/sfx/soundcmd.cpp @@ -0,0 +1,567 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sfx/iterator.h" // for SongIteratorStatus +#include "sci/sfx/soundcmd.h" + +namespace Sci { + +#define SCI1_SOUND_FLAG_MAY_PAUSE 1 /* Only here for completeness; The interpreter doesn't touch this bit */ +#define SCI1_SOUND_FLAG_SCRIPTED_PRI 2 /* but does touch this */ + +#define FROBNICATE_HANDLE(reg) ((reg).segment << 16 | (reg).offset) +#define DEFROBNICATE_HANDLE(handle) (make_reg((handle >> 16) & 0xffff, handle & 0xffff)) + +/* Sound status */ +enum { + _K_SOUND_STATUS_STOPPED = 0, + _K_SOUND_STATUS_INITIALIZED = 1, + _K_SOUND_STATUS_PAUSED = 2, + _K_SOUND_STATUS_PLAYING = 3 +}; + +static void script_set_priority(ResourceManager *resMan, SegManager *segMan, SfxState *state, reg_t obj, int priority) { + int song_nr = GET_SEL32V(segMan, obj, number); + Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0); + int flags = GET_SEL32V(segMan, obj, flags); + + if (priority == -1) { + if (song->data[0] == 0xf0) + priority = song->data[1]; + else + warning("Attempt to unset song priority when there is no built-in value"); + + flags &= ~SCI1_SOUND_FLAG_SCRIPTED_PRI; + } else flags |= SCI1_SOUND_FLAG_SCRIPTED_PRI; + + state->sfx_song_renice(FROBNICATE_HANDLE(obj), priority); + PUT_SEL32V(segMan, obj, flags, flags); +} + +SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id) { + Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0); + + if (!song) + return NULL; + + return songit_new(song->data, song->size, type, id); +} + +void process_sound_events(EngineState *s) { /* Get all sound events, apply their changes to the heap */ + int result; + SongHandle handle; + int cue; + SegManager *segMan = s->_segMan; + + if (getSciVersion() > SCI_VERSION_01) + return; + // SCI1 and later explicitly poll for everything + + while ((result = s->_sound.sfx_poll(&handle, &cue))) { + reg_t obj = DEFROBNICATE_HANDLE(handle); + if (!s->_segMan->isObject(obj)) { + warning("Non-object %04x:%04x received sound signal (%d/%d)", PRINT_REG(obj), result, cue); + return; + } + + switch (result) { + + case SI_LOOP: + debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x looped (to %d)\n", + PRINT_REG(obj), cue); + /* PUT_SEL32V(segMan, obj, loops, GET_SEL32V(segMan, obj, loop) - 1);*/ + PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); + break; + + case SI_RELATIVE_CUE: + debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d\n", + PRINT_REG(obj), cue); + PUT_SEL32V(segMan, obj, signal, cue + 0x7f); + break; + + case SI_ABSOLUTE_CUE: + debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d\n", + PRINT_REG(obj), cue); + PUT_SEL32V(segMan, obj, signal, cue); + break; + + case SI_FINISHED: + debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished\n", + PRINT_REG(obj)); + PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); + PUT_SEL32V(segMan, obj, state, _K_SOUND_STATUS_STOPPED); + break; + + default: + warning("Unexpected result from sfx_poll: %d", result); + break; + } + } +} + +#define SOUNDCOMMAND(x) _soundCommands.push_back(new SciSoundCommand(#x, &SoundCommandParser::x)) + +SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segMan, SfxState *state, AudioPlayer *audio, SciVersion doSoundVersion) : + _resMan(resMan), _segMan(segMan), _state(state), _audio(audio), _doSoundVersion(doSoundVersion) { + + switch (doSoundVersion) { + case SCI_VERSION_0_EARLY: + SOUNDCOMMAND(cmdInitHandle); + SOUNDCOMMAND(cmdPlayHandle); + SOUNDCOMMAND(cmdDummy); + SOUNDCOMMAND(cmdDisposeHandle); + SOUNDCOMMAND(cmdMuteSound); + SOUNDCOMMAND(cmdStopHandle); + SOUNDCOMMAND(cmdSuspendHandle); + SOUNDCOMMAND(cmdResumeHandle); + SOUNDCOMMAND(cmdVolume); + SOUNDCOMMAND(cmdHandlePriority); + SOUNDCOMMAND(cmdFadeHandle); + SOUNDCOMMAND(cmdGetPolyphony); + SOUNDCOMMAND(cmdGetPlayNext); + break; + case SCI_VERSION_1_EARLY: + SOUNDCOMMAND(cmdVolume); + SOUNDCOMMAND(cmdMuteSound); + SOUNDCOMMAND(cmdDummy); + SOUNDCOMMAND(cmdGetPolyphony); + SOUNDCOMMAND(cmdUpdateHandle); + SOUNDCOMMAND(cmdInitHandle); + SOUNDCOMMAND(cmdDisposeHandle); + SOUNDCOMMAND(cmdPlayHandle); + SOUNDCOMMAND(cmdStopHandle); + SOUNDCOMMAND(cmdSuspendHandle); + SOUNDCOMMAND(cmdFadeHandle); + SOUNDCOMMAND(cmdUpdateCues); + SOUNDCOMMAND(cmdSendMidi); + SOUNDCOMMAND(cmdReverb); + SOUNDCOMMAND(cmdHoldHandle); + break; + case SCI_VERSION_1_LATE: + SOUNDCOMMAND(cmdVolume); + SOUNDCOMMAND(cmdMuteSound); + SOUNDCOMMAND(cmdDummy); + SOUNDCOMMAND(cmdGetPolyphony); + SOUNDCOMMAND(cmdGetAudioCapability); + SOUNDCOMMAND(cmdSuspendSound); + SOUNDCOMMAND(cmdInitHandle); + SOUNDCOMMAND(cmdDisposeHandle); + SOUNDCOMMAND(cmdPlayHandle); + SOUNDCOMMAND(cmdStopHandle); + SOUNDCOMMAND(cmdSuspendHandle); + SOUNDCOMMAND(cmdFadeHandle); + SOUNDCOMMAND(cmdHoldHandle); + SOUNDCOMMAND(cmdDummy); + SOUNDCOMMAND(cmdSetHandleVolume); + SOUNDCOMMAND(cmdSetHandlePriority); + SOUNDCOMMAND(cmdSetHandleLoop); + SOUNDCOMMAND(cmdUpdateCues); + SOUNDCOMMAND(cmdSendMidi); + SOUNDCOMMAND(cmdReverb); + SOUNDCOMMAND(cmdUpdateVolumePriority); + break; + default: + warning("Sound command parser: unknown DoSound type %d", doSoundVersion); + break; + } +} + +SoundCommandParser::~SoundCommandParser() { +} + +reg_t SoundCommandParser::parseCommand(int argc, reg_t *argv, reg_t acc) { + uint16 command = argv[0].toUint16(); + reg_t obj = (argc > 1) ? argv[1] : NULL_REG; + SongHandle handle = FROBNICATE_HANDLE(obj); + int value = (argc > 2) ? argv[2].toSint16() : 0; + _acc = acc; + + if (argc > 5) { // for cmdSendMidi + _midiCmd = argv[3].toUint16() == 0xff ? + 0xe0 : /* Pitch wheel */ + 0xb0; /* argv[3].toUint16() is actually a controller number */ + _controller = argv[3].toUint16(); + _param = argv[4].toUint16(); + } + + if (command >= 0 && command < _soundCommands.size()) { + debugC(2, kDebugLevelSound, "%s", _soundCommands[command]->desc); + (this->*(_soundCommands[command]->sndCmd))(obj, handle, value); + } else { + warning("Invalid sound command requested (%d), valid range is 0-%d", command, _soundCommands.size() - 1); + } + + return _acc; +} + +void SoundCommandParser::cmdInitHandle(reg_t obj, SongHandle handle, int value) { + if (!obj.segment) + return; + + SongIteratorType type = (_doSoundVersion == SCI_VERSION_0_EARLY) ? SCI_SONG_ITERATOR_TYPE_SCI0 : SCI_SONG_ITERATOR_TYPE_SCI1; + int number = GET_SEL32V(_segMan, obj, number); + + if (_doSoundVersion != SCI_VERSION_0_EARLY) { + if (GET_SEL32V(_segMan, obj, nodePtr)) { + _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + _state->sfx_remove_song(handle); + } + } + + // Some games try to init non-existing sounds (e.g. KQ6) + if (_doSoundVersion == SCI_VERSION_1_LATE) { + if (!obj.segment || !_resMan->testResource(ResourceId(kResourceTypeSound, value))) + return; + } + + _state->sfx_add_song(build_iterator(_resMan, number, type, handle), 0, handle, number); + + if (_doSoundVersion == SCI_VERSION_0_EARLY) { + PUT_SEL32V(_segMan, obj, state, _K_SOUND_STATUS_INITIALIZED); + } else { + PUT_SEL32(_segMan, obj, nodePtr, obj); + } + + PUT_SEL32(_segMan, obj, handle, obj); +} + +void SoundCommandParser::cmdPlayHandle(reg_t obj, SongHandle handle, int value) { + if (!obj.segment) + return; + + _state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING); + _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, loop)); + + if (_doSoundVersion == SCI_VERSION_0_EARLY) { + PUT_SEL32V(_segMan, obj, state, _K_SOUND_STATUS_PLAYING); + } else if (_doSoundVersion == SCI_VERSION_1_EARLY) { + _state->sfx_song_renice(handle, GET_SEL32V(_segMan, obj, pri)); + RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) value; /* Too lazy to look up a default value for this */ + _state->_songlib.setSongRestoreBehavior(handle, rb); + PUT_SEL32V(_segMan, obj, signal, 0); + } else if (_doSoundVersion == SCI_VERSION_1_LATE) { + int looping = GET_SEL32V(_segMan, obj, loop); + //int vol = GET_SEL32V(_segMan, obj, vol); + int pri = GET_SEL32V(_segMan, obj, pri); + int sampleLen = 0; + Song *song = _state->_songlib.findSong(handle); + int songNumber = GET_SEL32V(_segMan, obj, number); + + if (GET_SEL32V(_segMan, obj, nodePtr) && (song && songNumber != song->_resourceNum)) { + _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + _state->sfx_remove_song(handle); + PUT_SEL32(_segMan, obj, nodePtr, NULL_REG); + } + + if (!GET_SEL32V(_segMan, obj, nodePtr) && obj.segment) { + // In SCI1.1 games, sound effects are started from here. If we can find + // a relevant audio resource, play it, otherwise switch to synthesized + // effects. If the resource exists, play it using map 65535 (sound + // effects map) + if (_resMan->testResource(ResourceId(kResourceTypeAudio, songNumber)) && + getSciVersion() >= SCI_VERSION_1_1) { + // Found a relevant audio resource, play it + _audio->stopAudio(); + warning("Initializing audio resource instead of requested sound resource %d", songNumber); + sampleLen = _audio->startAudio(65535, songNumber); + // Also create iterator, that will fire SI_FINISHED event, when the sound is done playing + _state->sfx_add_song(new_timer_iterator(sampleLen), 0, handle, songNumber); + } else { + if (!_resMan->testResource(ResourceId(kResourceTypeSound, songNumber))) { + warning("Could not open song number %d", songNumber); + // Send a "stop handle" event so that the engine won't wait forever here + _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); + return; + } + debugC(2, kDebugLevelSound, "Initializing song number %d\n", songNumber); + _state->sfx_add_song(build_iterator(_resMan, songNumber, SCI_SONG_ITERATOR_TYPE_SCI1, + handle), 0, handle, songNumber); + } + + PUT_SEL32(_segMan, obj, nodePtr, obj); + PUT_SEL32(_segMan, obj, handle, obj); + } + + if (obj.segment) { + _state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING); + _state->sfx_song_set_loops(handle, looping); + _state->sfx_song_renice(handle, pri); + PUT_SEL32V(_segMan, obj, signal, 0); + } + } +} + +void SoundCommandParser::cmdDummy(reg_t obj, SongHandle handle, int value) { + warning("cmdDummy invoked"); // not supposed to occur +} + +void SoundCommandParser::changeHandleStatus(reg_t obj, SongHandle handle, int newStatus) { + if (obj.segment) { + _state->sfx_song_set_status(handle, newStatus); + if (_doSoundVersion == SCI_VERSION_0_EARLY) + PUT_SEL32V(_segMan, obj, state, newStatus); + } +} + +void SoundCommandParser::cmdDisposeHandle(reg_t obj, SongHandle handle, int value) { + changeHandleStatus(obj, handle, SOUND_STATUS_STOPPED); + + if (obj.segment) { + _state->sfx_remove_song(handle); + + if (_doSoundVersion == SCI_VERSION_0_EARLY) + PUT_SEL32V(_segMan, obj, handle, 0x0000); + } +} + +void SoundCommandParser::cmdStopHandle(reg_t obj, SongHandle handle, int value) { + changeHandleStatus(obj, handle, SOUND_STATUS_STOPPED); + + if (_doSoundVersion != SCI_VERSION_0_EARLY) + PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); +} + +void SoundCommandParser::cmdSuspendHandle(reg_t obj, SongHandle handle, int value) { + if (_doSoundVersion == SCI_VERSION_0_EARLY) + changeHandleStatus(obj, handle, SOUND_STATUS_SUSPENDED); + else + changeHandleStatus(obj, handle, value ? SOUND_STATUS_SUSPENDED : SOUND_STATUS_PLAYING); +} + +void SoundCommandParser::cmdResumeHandle(reg_t obj, SongHandle handle, int value) { + changeHandleStatus(obj, handle, SOUND_STATUS_PLAYING); +} + +void SoundCommandParser::cmdMuteSound(reg_t obj, SongHandle handle, int value) { + // TODO + + /* if there's a parameter, we're setting it. Otherwise, we're querying it. */ + /*int param = UPARAM_OR_ALT(1,-1); + + if (param != -1) + s->acc = s->sound_server->command(s, SOUND_COMMAND_SET_MUTE, 0, param); + else + s->acc = s->sound_server->command(s, SOUND_COMMAND_GET_MUTE, 0, 0);*/ +} + +void SoundCommandParser::cmdVolume(reg_t obj, SongHandle handle, int value) { + if (obj != SIGNAL_REG) + _state->sfx_setVolume(obj.toSint16()); + + _acc = make_reg(0, _state->sfx_getVolume()); +} + +void SoundCommandParser::cmdHandlePriority(reg_t obj, SongHandle handle, int value) { + if (obj.segment) { + _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, loop)); + script_set_priority(_resMan, _segMan, _state, obj, GET_SEL32V(_segMan, obj, pri)); + } +} + +void SoundCommandParser::cmdFadeHandle(reg_t obj, SongHandle handle, int value) { + /*s->sound_server->command(s, SOUND_COMMAND_FADE_HANDLE, obj, 120);*/ /* Fade out in 2 secs */ + /* FIXME: The next couple of lines actually STOP the handle, rather + ** than fading it! */ + if (obj.segment) { + _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + if (_doSoundVersion == SCI_VERSION_0_EARLY) + PUT_SEL32V(_segMan, obj, state, SOUND_STATUS_STOPPED); + PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); + } + +#if 0 + fade_params_t fade; + if (obj.segment) { + fade.final_volume = argv[2].toUint16(); + fade.ticks_per_step = argv[3].toUint16(); + fade.step_size = argv[4].toUint16(); + fade.action = argv[5].toUint16() ? + FADE_ACTION_FADE_AND_STOP : + FADE_ACTION_FADE_AND_CONT; + + s->_sound.sfx_song_set_fade(handle, &fade); + + /* FIXME: The next couple of lines actually STOP the handle, rather + ** than fading it! */ + if (argv[5].toUint16()) { + PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); + s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + } else { + // FIXME: Support fade-and-continue. For now, send signal right away. + PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); + } + } +#endif +} + +void SoundCommandParser::cmdGetPolyphony(reg_t obj, SongHandle handle, int value) { + _acc = make_reg(0, _state->sfx_get_player_polyphony()); +} + +void cmdGetPlayNext(EngineState *s, reg_t obj, SongHandle handle, int value) { + // TODO + // _state->sfx_all_stop(); +} + +void SoundCommandParser::cmdUpdateHandle(reg_t obj, SongHandle handle, int value) { + // FIXME: Get these from the sound server + int signal = 0; + int min = 0; + int sec = 0; + int frame = 0; + + // FIXME: Update the sound server state with 'vol' + //int vol = GET_SEL32V(segMan, obj, vol); + + _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, loop)); + _state->sfx_song_renice(handle, GET_SEL32V(_segMan, obj, pri)); + + debugC(2, kDebugLevelSound, "[sound01-update-handle] -- CUE %04x:%04x", PRINT_REG(obj)); + + PUT_SEL32V(_segMan, obj, signal, signal); + PUT_SEL32V(_segMan, obj, min, min); + PUT_SEL32V(_segMan, obj, sec, sec); + PUT_SEL32V(_segMan, obj, frame, frame); +} + +void SoundCommandParser::cmdUpdateCues(reg_t obj, SongHandle handle, int value) { + int signal = 0; + int min = 0; + int sec = 0; + int frame = 0; + int result = SI_LOOP; // small hack + int cue = 0; + + while (result == SI_LOOP) + result = _state->sfx_poll_specific(handle, &cue); + + switch (result) { + case SI_ABSOLUTE_CUE: + signal = cue; + debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Absolute Cue: %d\n", + PRINT_REG(obj), signal); + + PUT_SEL32V(_segMan, obj, signal, signal); + break; + + case SI_RELATIVE_CUE: + signal = cue; + debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Relative Cue: %d\n", + PRINT_REG(obj), cue); + + /* FIXME to match commented-out semantics + * below, with proper storage of dataInc and + * signal in the iterator code. */ + PUT_SEL32V(_segMan, obj, dataInc, signal); + PUT_SEL32V(_segMan, obj, signal, signal); + break; + + case SI_FINISHED: + debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x\n", PRINT_REG(obj)); + PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); + break; + + case SI_LOOP: + break; // Doesn't happen + } + + //switch (signal) { + //case 0x00: + // if (dataInc!=GET_SEL32V(segMan, obj, dataInc)) { + // PUT_SEL32V(segMan, obj, dataInc, dataInc); + // PUT_SEL32V(segMan, obj, signal, dataInc+0x7f); + // } else { + // PUT_SEL32V(segMan, obj, signal, signal); + // } + // break; + //case 0xFF: // May be unnecessary + // s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + // break; + //default : + // if (dataInc!=GET_SEL32V(segMan, obj, dataInc)) { + // PUT_SEL32V(segMan, obj, dataInc, dataInc); + // PUT_SEL32V(segMan, obj, signal, dataInc + 0x7f); + // } else { + // PUT_SEL32V(segMan, obj, signal, signal); + // } + // break; + //} + + PUT_SEL32V(_segMan, obj, min, min); + PUT_SEL32V(_segMan, obj, sec, sec); + PUT_SEL32V(_segMan, obj, frame, frame); +} + +void SoundCommandParser::cmdSendMidi(reg_t obj, SongHandle handle, int value) { + int channel = value; + + _state->sfx_send_midi(handle, channel, _midiCmd, _controller, _param); +} + +void SoundCommandParser::cmdReverb(reg_t obj, SongHandle handle, int value) { + // TODO +} +void SoundCommandParser::cmdHoldHandle(reg_t obj, SongHandle handle, int value) { + _state->sfx_song_set_hold(handle, value); +} + +void SoundCommandParser::cmdGetAudioCapability(reg_t obj, SongHandle handle, int value) { + // Tests for digital audio support + _acc = make_reg(0, 1); +} + +void SoundCommandParser::cmdGetPlayNext(reg_t obj, SongHandle handle, int value) { +} + +void SoundCommandParser::cmdSetHandleVolume(reg_t obj, SongHandle handle, int value) { + // TODO +} + +void SoundCommandParser::cmdSetHandlePriority(reg_t obj, SongHandle handle, int value) { + script_set_priority(_resMan, _segMan, _state, obj, value); +} + +void SoundCommandParser::cmdSetHandleLoop(reg_t obj, SongHandle handle, int value) { + if (!GET_SEL32(_segMan, obj, nodePtr).isNull()) { + uint16 looping = value; + + if (looping < 65535) + looping = 1; + + _state->sfx_song_set_loops(handle, looping); + PUT_SEL32V(_segMan, obj, loop, looping); + } +} + +void SoundCommandParser::cmdSuspendSound(reg_t obj, SongHandle handle, int value) { + // TODO +} + +void SoundCommandParser::cmdUpdateVolumePriority(reg_t obj, SongHandle handle, int value) { + // TODO +} + +} // End of namespace Sci diff --git a/engines/sci/sfx/soundcmd.h b/engines/sci/sfx/soundcmd.h new file mode 100644 index 0000000000..60efa3b1dc --- /dev/null +++ b/engines/sci/sfx/soundcmd.h @@ -0,0 +1,91 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCI_SOUNDCMD_H +#define SCI_SOUNDCMD_H + +#include "sci/engine/state.h" + +namespace Sci { + +class SoundCommandParser; +typedef void (SoundCommandParser::*SoundCommand)(reg_t obj, SongHandle handle, int value); + +struct SciSoundCommand { + SciSoundCommand(const char* d, SoundCommand c) : desc(d), sndCmd(c) {} + const char* desc; + SoundCommand sndCmd; +}; + +class SoundCommandParser { +public: + SoundCommandParser(ResourceManager *resMan, SegManager *segMan, SfxState *state, AudioPlayer *audio, SciVersion doSoundVersion); + ~SoundCommandParser(); + + reg_t parseCommand(int argc, reg_t *argv, reg_t acc); + +private: + Common::Array<SciSoundCommand*> _soundCommands; + ResourceManager *_resMan; + SegManager *_segMan; + SfxState *_state; + AudioPlayer *_audio; + SciVersion _doSoundVersion; + reg_t _acc; + int _midiCmd, _controller, _param; + + void cmdInitHandle(reg_t obj, SongHandle handle, int value); + void cmdPlayHandle(reg_t obj, SongHandle handle, int value); + void cmdDummy(reg_t obj, SongHandle handle, int value); + void cmdMuteSound(reg_t obj, SongHandle handle, int value); + void cmdSuspendHandle(reg_t obj, SongHandle handle, int value); + void cmdResumeHandle(reg_t obj, SongHandle handle, int value); + void cmdStopHandle(reg_t obj, SongHandle handle, int value); + void cmdDisposeHandle(reg_t obj, SongHandle handle, int value); + void cmdVolume(reg_t obj, SongHandle handle, int value); + void cmdHandlePriority(reg_t obj, SongHandle handle, int value); + void cmdFadeHandle(reg_t obj, SongHandle handle, int value); + void cmdGetPolyphony(reg_t obj, SongHandle handle, int value); + void cmdGetPlayNext(reg_t obj, SongHandle handl, int valuee); + + void initHandle(reg_t obj, SongHandle handle, bool isSci1); + void changeHandleStatus(reg_t obj, SongHandle handle, int newStatus); + + void cmdUpdateHandle(reg_t obj, SongHandle handle, int value); + void cmdUpdateCues(reg_t obj, SongHandle handle, int value); + void cmdSendMidi(reg_t obj, SongHandle handle, int value); + void cmdReverb(reg_t obj, SongHandle handle, int value); + void cmdHoldHandle(reg_t obj, SongHandle handle, int value); + void cmdGetAudioCapability(reg_t obj, SongHandle handle, int value); + void cmdSetHandleVolume(reg_t obj, SongHandle handle, int value); + void cmdSetHandlePriority(reg_t obj, SongHandle handle, int value); + void cmdSetHandleLoop(reg_t obj, SongHandle handle, int value); + void cmdSuspendSound(reg_t obj, SongHandle handle, int value); + void cmdUpdateVolumePriority(reg_t obj, SongHandle handle, int value); +}; + +} // End of namespace Sci + +#endif // SCI_SOUNDCMD_H |