aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorFilippos Karapetis2009-11-12 15:24:11 +0000
committerFilippos Karapetis2009-11-12 15:24:11 +0000
commitfbfafb576e14bdd31d69eb1b6a262bb8d667e852 (patch)
tree0a31b65e91f3c444cb821e504726f651053a9b6d /engines/sci
parent3d796d6c088677ab30f1aae0226651f46d46013f (diff)
downloadscummvm-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.cpp964
-rw-r--r--engines/sci/engine/savegame.cpp7
-rw-r--r--engines/sci/engine/state.cpp2
-rw-r--r--engines/sci/engine/state.h3
-rw-r--r--engines/sci/module.mk1
-rw-r--r--engines/sci/sci.cpp5
-rw-r--r--engines/sci/sfx/soundcmd.cpp567
-rw-r--r--engines/sci/sfx/soundcmd.h91
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