aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudvig Strigeus2001-11-14 18:40:39 +0000
committerLudvig Strigeus2001-11-14 18:40:39 +0000
commitb8d259d60eed2f8edc321dcba6116bddabbc35e8 (patch)
tree84d98395311081717250ea496df496fe88b5707d
parent279d5b2fd73057dc48b9f18a8753a2a5cff1c2e6 (diff)
downloadscummvm-rg350-b8d259d60eed2f8edc321dcba6116bddabbc35e8.tar.gz
scummvm-rg350-b8d259d60eed2f8edc321dcba6116bddabbc35e8.tar.bz2
scummvm-rg350-b8d259d60eed2f8edc321dcba6116bddabbc35e8.zip
music support,
fixed timing bugs svn-id: r3491
-rw-r--r--Makefile3
-rw-r--r--actor.cpp2
-rw-r--r--gfx.cpp2
-rw-r--r--gui.cpp69
-rw-r--r--gui.h2
-rw-r--r--imuse.cpp2529
-rw-r--r--resource.cpp4
-rw-r--r--saveload.cpp44
-rw-r--r--script_v1.cpp2
-rw-r--r--script_v2.cpp2
-rw-r--r--scumm.h43
-rw-r--r--scummvm.cpp20
-rw-r--r--scummvm.dsp10
-rw-r--r--sdl.cpp287
-rw-r--r--sound.cpp140
-rw-r--r--sound.h358
-rw-r--r--string.cpp2
-rw-r--r--windows.cpp143
18 files changed, 3292 insertions, 370 deletions
diff --git a/Makefile b/Makefile
index 35030e14be..e63a7f084f 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,8 @@ INCS = scumm.h scummsys.h stdafx.h
OBJS = actor.o boxes.o costume.o gfx.o object.o resource.o \
saveload.o script.o scummvm.o sound.o string.o \
- sys.o verbs.o sdl.o script_v1.o script_v2.o debug.o gui.o
+ sys.o verbs.o sdl.o script_v1.o script_v2.o debug.o gui.o \
+ imuse.o
DISTFILES=actor.cpp boxes.cpp costume.cpp gfx.cpp object.cpp resource.cpp \
saveload.cpp script.cpp scummvm.cpp sound.cpp string.cpp \
diff --git a/actor.cpp b/actor.cpp
index d3eb305abb..6f6d75897e 100644
--- a/actor.cpp
+++ b/actor.cpp
@@ -585,6 +585,8 @@ void Scumm::showActors() {
void Scumm::stopTalk() {
int act;
+ stopTalkSound();
+
_haveMsg = 0;
_talkDelay = 0;
diff --git a/gfx.cpp b/gfx.cpp
index 8efe3f4ae1..ddbf4dd4d4 100644
--- a/gfx.cpp
+++ b/gfx.cpp
@@ -1396,7 +1396,7 @@ void Scumm::unkScreenEffect7(int a) {
tab_2[i] += tab_1[i];
updateScreen(this);
- waitForTimer(this,3);
+ waitForTimer(this,30);
}
}
diff --git a/gui.cpp b/gui.cpp
index a771762e0f..4eb4d66b99 100644
--- a/gui.cpp
+++ b/gui.cpp
@@ -2,6 +2,11 @@
#include "scumm.h"
#include "gui.h"
+enum {
+ SAVELOAD_DIALOG,
+ PAUSE_DIALOG
+};
+
void Gui::draw(int start,int end) {
int i;
@@ -249,6 +254,12 @@ const GuiWidget save_load_dialog[] = {
{0}
};
+const GuiWidget pause_dialog[] = {
+ {GUI_TEXT,0x01,GWF_DEFAULT,50,80,220,16,0,10},
+ {0},
+};
+
+
void Gui::handleCommand(int cmd) {
int lastEdit = _editString;
showCaret(false);
@@ -332,18 +343,20 @@ const byte string_map_table_v6[] = {
99, /* Cancel */
100, /* Quit */
101, /* Ok */
+ 93, /* Game paused */
};
const byte string_map_table_v5[] = {
0, /* How may I serve you? */
20, /* Select a game to LOAD */
- 21, /* Name your SAVE game */
+ 19, /* Name your SAVE game */
7, /* Save */
8, /* Load */
9, /* Play */
10, /* Cancel */
11, /* Quit */
12, /* Ok */
+ 4, /* Game paused */
};
const char *Gui::queryString(int string, int id) {
@@ -399,27 +412,28 @@ void Gui::editString(int i) {
}
void Gui::addLetter(byte letter) {
- if (_editString==-1)
- return;
+ switch(_dialog) {
+ case SAVELOAD_DIALOG:
+ if (_editString==-1)
+ return;
- if (letter==13) {
- handleCommand(8);
- return;
- }
+ if (letter==13) {
+ handleCommand(8);
+ return;
+ }
- if (letter>=32 && letter<128 && _editLen < SAVEGAME_NAME_LEN-1) {
- game_names[_editString][_editLen++] = letter;
- } else if (letter==8 && _editLen>0) {
- _editLen--;
+ if (letter>=32 && letter<128 && _editLen < SAVEGAME_NAME_LEN-1) {
+ game_names[_editString][_editLen++] = letter;
+ } else if (letter==8 && _editLen>0) {
+ _editLen--;
+ }
+ showCaret(true);
+ break;
+ case PAUSE_DIALOG:
+ if (letter==32)
+ close();
+ break;
}
- showCaret(true);
-}
-
-void Gui::saveLoadDialog() {
- _widgets[0] = save_load_dialog;
- _editString = -1;
- _cur_page = 0;
- _active = 1;
}
byte Gui::getDefaultColor(int color) {
@@ -431,7 +445,6 @@ byte Gui::getDefaultColor(int color) {
}
}
-
void Gui::init(Scumm *s) {
_s = s;
_bgcolor = getDefaultColor(0);
@@ -447,6 +460,7 @@ void Gui::loop() {
draw(0,100);
_s->_cursorAnimate++;
_s->gdi._cursorActive = 1;
+ _s->pauseSounds(true);
}
_s->getKeyInput(0);
@@ -471,5 +485,20 @@ void Gui::close() {
_s->_fullRedraw = true;
_s->_completeScreenRedraw = true;
_s->_cursorAnimate--;
+ _s->pauseSounds(false);
_active = false;
}
+
+void Gui::saveLoadDialog() {
+ _widgets[0] = save_load_dialog;
+ _editString = -1;
+ _cur_page = 0;
+ _active = true;
+ _dialog = SAVELOAD_DIALOG;
+}
+
+void Gui::pause() {
+ _widgets[0] = pause_dialog;
+ _active = true;
+ _dialog = PAUSE_DIALOG;
+}
diff --git a/gui.h b/gui.h
index 7e47d2c6db..d8e4277e99 100644
--- a/gui.h
+++ b/gui.h
@@ -43,6 +43,7 @@ struct Gui {
byte _active;
byte _clickTimer;
byte _cur_page;
+ byte _dialog;
int _clickWidget;
char *_queryMess;
@@ -77,6 +78,7 @@ struct Gui {
void saveLoadDialog();
void queryMessage(const char *msg, const char *alts);
byte getDefaultColor(int color);
+ void pause();
};
#endif \ No newline at end of file
diff --git a/imuse.cpp b/imuse.cpp
new file mode 100644
index 0000000000..1ae3de9ae3
--- /dev/null
+++ b/imuse.cpp
@@ -0,0 +1,2529 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "sound.h"
+
+#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
+
+#define TICKS_PER_BEAT 480
+#define TEMPO_BASE 0x400000
+#define HARDWARE_TYPE 5
+#define SYSEX_ID 0x7D
+#define SPECIAL_CHANNEL 9
+
+#define TRIGGER_ID 0
+#define COMMAND_ID 1
+
+#ifdef SAMNMAX
+#define MDHD_TAG "MDpg"
+#else
+#define MDHD_TAG "MDhd"
+#endif
+
+static int clamp(int val, int min, int max) {
+ if (val<min)
+ return min;
+ if (val>max)
+ return max;
+ return val;
+}
+
+static int transpose_clamp(int a, int b, int c) {
+ if (b>a) a += (b - a + 11) / 12 * 12;
+ if (c<a) a -= (a - c + 11) / 12 * 12;
+ return a;
+}
+
+uint32 get_delta_time(byte **s) {
+ byte *d = *s,b;
+ uint32 time = 0;
+ do {
+ b = *d++;
+ time = (time<<7) | (b&0x7F);
+ } while (b&0x80);
+ *s = d;
+ return time;
+}
+
+uint read_word(byte *a) {
+ return (a[0]<<8) + a[1];
+}
+
+void skip_midi_cmd(byte **song_ptr) {
+ byte *s, code;
+
+ const byte num_skip[] = {
+ 2,2,2,2,1,1,2
+ };
+
+ s = *song_ptr;
+
+ code = *s++;
+
+ if (code<0x80) {
+ s = NULL;
+ } else if (code<0xF0) {
+ s += num_skip[(code&0x70)>>4];
+ } else {
+ if (code==0xF0 || code==0xF7 || code==0xFF && *s++ != 0x2F) {
+ s += get_delta_time(&s);
+ } else {
+ s = NULL;
+ }
+ }
+ *song_ptr = s;
+}
+
+int is_note_cmd(byte **a, IsNoteCmdData *isnote) {
+ byte *s = *a;
+ byte code;
+
+ code = *s++;
+
+ switch(code>>4) {
+ case 8: /* key off */
+ isnote->chan = code&0xF;
+ isnote->note = *s++;
+ isnote->vel = *s++;
+ *a = s;
+ return 1;
+ case 9: /* key on */
+ isnote->chan = code&0xF;
+ isnote->note = *s++;
+ isnote->vel = *s++;
+ *a = s;
+ if (isnote->vel)
+ return 2;
+ return 1;
+ case 0xA:
+ case 0xB:
+ case 0xE:
+ s++;
+ case 0xC:
+ case 0xD:
+ s++;
+ break;
+ case 0xF:
+ if (code==0xF0 || code==0xF7 || code==0xFF && *s++ != 0x2F) {
+ s += get_delta_time(&s);
+ break;
+ }
+ return -1;
+ default:
+ return -1;
+ }
+ *a = s;
+ return 0;
+}
+
+/**********************************************************************/
+
+byte *SoundEngine::findTag(int sound, char *tag, int index) {
+ byte *ptr = _base_sounds[sound];
+ int32 size,pos;
+
+ if (ptr==NULL) {
+ debug(1, "SoundEngine::findTag completely failed finding sound %d", sound);
+ return 0;
+ }
+
+ ptr += 8;
+ size = READ_BE_UINT32_UNALIGNED(ptr);
+ ptr += 4;
+
+ pos = 0;
+ while (pos < size) {
+ if (!memcmp(ptr + pos, tag, 4) && !index--)
+ return ptr + pos + 8;
+ pos += READ_BE_UINT32_UNALIGNED(ptr + pos + 4) + 8;
+ }
+ debug(1, "SoundEngine::findTag failed finding sound %d", sound);
+ return NULL;
+
+}
+
+bool SoundEngine::start_sound(int sound) {
+ Player *player;
+ void *mdhd;
+
+ mdhd = findTag(sound, MDHD_TAG, 0);
+ if (!mdhd)
+ return false;
+
+ player = allocate_player(128);
+ if (!player)
+ return false;
+
+ player->clear();
+ return player->start_sound(sound);
+}
+
+
+Player *SoundEngine::allocate_player(byte priority) {
+ Player *player = _players, *best = NULL;
+ int i;
+ byte bestpri = 255;
+
+ for (i=ARRAYSIZE(_players); i!=0; i--, player++) {
+ if (!player->_active)
+ return player;
+ if (player->_priority < bestpri) {
+ best = player;
+ bestpri = player->_priority;
+ }
+ }
+
+ if (bestpri < priority)
+ return best;
+
+ debug(1, "Denying player request");
+ return NULL;
+}
+
+void SoundEngine::init_players() {
+ Player *player = _players;
+ int i;
+
+ for (i=ARRAYSIZE(_players); i!=0; i--, player++) {
+ player->_active = false;
+ player->_se = this;
+ }
+}
+
+void SoundEngine::init_sustaining_notes() {
+ SustainingNotes *next = NULL, *sn = _sustaining_notes;
+ int i;
+
+ _sustain_notes_used = NULL;
+ _sustain_notes_head = NULL;
+
+ for (i=ARRAYSIZE(_sustaining_notes);i!=0; i--,sn++) {
+ sn->next = next;
+ next = sn;
+ }
+ _sustain_notes_free = next;
+}
+
+void SoundEngine::init_volume_fader() {
+ VolumeFader *vf = _volume_fader;
+ int i;
+
+ for (i=ARRAYSIZE(_volume_fader); i!=0; i--, vf++)
+ vf->initialize();
+
+ _active_volume_faders = false;
+}
+
+void SoundEngine::init_parts() {
+ Part *part;
+ int i;
+ MidiChannel *mc;
+
+ for (i=ARRAYSIZE(_parts),part=_parts; i!=0; i--, part++)
+ part->init(this);
+
+ for(i=0,mc=_midi_channels; i!=ARRAYSIZE(_midi_channels);i++,mc++)
+ mc->init(i);
+}
+
+int SoundEngine::stop_sound(int sound) {
+ Player *player = _players;
+ int i;
+ int r = -1;
+
+ for (i=ARRAYSIZE(_players); i!=0; i--,player++) {
+ if (player->_active && player->_id==sound) {
+ player->clear();
+ r = 0;
+ }
+ }
+ return r;
+}
+
+int SoundEngine::stop_all_sounds() {
+ Player *player = _players;
+ int i;
+
+ for (i=ARRAYSIZE(_players); i!=0; i--,player++) {
+ if (player->_active)
+ player->clear();
+ }
+ return 0;
+}
+
+void SoundEngine::on_timer() {
+ if (_locked || _paused)
+ return;
+ lock();
+ sequencer_timers();
+ expire_sustain_notes();
+ expire_volume_faders();
+ unlock();
+}
+
+void SoundEngine::sequencer_timers() {
+ Player *player = _players;
+ int i;
+
+ for (i=ARRAYSIZE(_players); i!=0; i--,player++) {
+ if (player->_active)
+ player->sequencer_timer();
+ }
+}
+
+void Player::sequencer_timer() {
+ byte *mtrk;
+ uint32 counter;
+ byte *song_ptr;
+
+ counter = _timer_counter + _timer_speed;
+ _timer_counter = counter&0xFFFF;
+ _cur_pos += counter>>16;
+ _tick_index += counter>>16;
+
+ if (_tick_index>=_ticks_per_beat) {
+ _beat_index += _tick_index/_ticks_per_beat;
+ _tick_index %= _ticks_per_beat;
+ }
+ if (_loop_counter && _beat_index >= _loop_from_beat && _tick_index >= _loop_from_tick) {
+ _loop_counter--;
+ jump(_track_index, _loop_to_beat, _loop_to_tick);
+ }
+ if (_next_pos <= _cur_pos) {
+ mtrk = _se->findTag(_song_index, "MTrk", _track_index);
+ if (!mtrk) {
+ warning("Sound %d was unloaded while active", _song_index);
+ clear();
+ } else {
+ song_ptr = mtrk + _song_offset;
+ _abort = false;
+
+ while (_next_pos <= _cur_pos) {
+ song_ptr = parse_midi(song_ptr);
+ if (!song_ptr || _abort)
+ return;
+ _next_pos += get_delta_time(&song_ptr);
+ }
+ _song_offset = song_ptr - mtrk;
+ }
+ }
+}
+
+void SoundEngine::handle_marker(uint id, byte data) {
+ uint16 *p;
+ uint pos;
+ int a;
+
+ pos = _queue_end;
+ if (pos == _queue_pos)
+ return;
+
+ if (_queue_adding && _queue_sound==id && data==_queue_marker)
+ return;
+
+ p = _cmd_queue[pos].array;
+
+ if (p[0] != TRIGGER_ID || p[1] != id || p[2] != data)
+ return;
+
+ _trigger_count--;
+ _queue_cleared = false;
+ do {
+ pos = (++pos) & (ARRAYSIZE(_cmd_queue)-1);
+ if (_queue_pos == pos)
+ break;
+ p = _cmd_queue[pos].array;
+ if (*p++ != COMMAND_ID)
+ break;
+ _queue_end = pos;
+
+ do_command(p[0],p[1],p[2],p[3],p[4],p[5],p[6],0);
+
+ if (_queue_cleared)
+ return;
+ pos = _queue_end;
+ } while (1);
+
+ _queue_end = pos;
+}
+
+int SoundEngine::get_channel_volume(uint a) {
+ if (a<8)
+ return _channel_volume_eff[a];
+ return _master_volume;
+}
+
+Part *SoundEngine::allocate_part(byte pri) {
+ Part *part,*best=NULL;
+ int i;
+
+ for (i=ARRAYSIZE(_parts),part=_parts; i!=0; i--,part++) {
+ if (!part->_player)
+ return part;
+ if (pri >= part->_pri_eff) {
+ pri = part->_pri_eff;
+ best = part;
+ }
+ }
+
+ if (best)
+ best->uninit();
+ else
+ debug(1, "Denying part request");
+ return best;
+}
+
+void SoundEngine::expire_sustain_notes() {
+ SustainingNotes *sn,*next;
+ Player *player;
+ uint32 counter;
+
+ for(sn=_sustain_notes_head; sn; sn = next) {
+ next = sn->next;
+ player = sn->player;
+
+ counter = sn->counter + player->_timer_speed;
+ sn->pos += counter>>16;
+ sn->counter = counter & 0xFFFF;
+
+ if (sn->pos >= sn->off_pos) {
+ player->key_off(sn->chan, sn->note);
+
+ /* Unlink the node */
+ if (next)
+ next->prev = sn->prev;
+ if (sn->prev)
+ sn->prev->next = next;
+ else
+ _sustain_notes_head = next;
+
+ /* And put it in the free list */
+ sn->next = _sustain_notes_free;
+ _sustain_notes_free = sn;
+ }
+ }
+}
+
+void SoundEngine::expire_volume_faders() {
+ VolumeFader *vf;
+ int i;
+
+ if (++_volume_fader_counter & 7)
+ return;
+
+ if (!_active_volume_faders)
+ return;
+
+ _active_volume_faders = false;
+ vf = _volume_fader;
+ for (i=ARRAYSIZE(_volume_fader); i!=0; i--,vf++) {
+ if (vf->active) {
+ _active_volume_faders = true;
+ vf->on_timer();
+ }
+ }
+}
+
+void VolumeFader::on_timer() {
+ byte newvol;
+
+ newvol = curvol + speed_hi;
+ speed_lo_counter += speed_lo;
+
+ if (speed_lo_counter >= speed_lo_max) {
+ speed_lo_counter -= speed_lo_max;
+ newvol += direction;
+ }
+
+ if (curvol!=newvol) {
+ if (!newvol) {
+ player->clear();
+ active = false;
+ return;
+ }
+ curvol = newvol;
+ player->set_vol(newvol);
+ }
+
+ if (!--num_steps) {
+ active = false;
+ }
+}
+
+int SoundEngine::get_sound_status(int sound) {
+ int i;
+ Player *player;
+
+ for (i=ARRAYSIZE(_players),player=_players; i!=0; i--,player++) {
+ if (player->_active && player->_id==(uint16)sound)
+ return 1;
+ }
+ return get_queue_sound_status(sound);
+}
+
+int SoundEngine::get_queue_sound_status(int sound) {
+ uint16 *a;
+ int i,j;
+
+ j = _queue_pos;
+ i = _queue_end;
+
+ while (i!=j) {
+ a = _cmd_queue[i].array;
+ if (a[0] == COMMAND_ID && a[1] == 8 && a[2] == (uint16)sound)
+ return 2;
+ i = (++i) & (ARRAYSIZE(_cmd_queue)-1);
+ }
+ return 0;
+}
+
+int SoundEngine::set_volchan(int sound, int volchan) {
+ int r;
+ int i;
+ int num;
+ Player *player,*best,*sameid;
+
+ r = get_volchan_entry(volchan);
+ if (r==-1)
+ return -1;
+
+ if (r >= 8) {
+ for(i=ARRAYSIZE(_players),player=_players; i!=0; i--,player++) {
+ if (player->_active && player->_id==(uint16)sound && player->_vol_chan!=(uint16)volchan) {
+ player->_vol_chan = volchan;
+ player->set_vol(player->_volume);
+ return 0;
+ }
+ }
+ return -1;
+ } else {
+ best = NULL;
+ num = 0;
+ sameid = NULL;
+ for(i=ARRAYSIZE(_players),player=_players; i!=0; i--,player++) {
+ if (player->_active) {
+ if (player->_vol_chan==(uint16)volchan) {
+ num++;
+ if (!best || player->_priority <= best->_priority)
+ best = player;
+ } else if (player->_id == (uint16)sound) {
+ sameid = player;
+ }
+ }
+ }
+ if (sameid==NULL)
+ return -1;
+ if (num >= r)
+ best->clear();
+ player->_vol_chan = volchan;
+ player->set_vol(player->_volume);
+ return 0;
+ }
+}
+
+int SoundEngine::clear_queue() {
+ _queue_adding = false;
+ _queue_cleared = true;
+ _queue_pos = 0;
+ _queue_end = 0;
+ _trigger_count = 0;
+ return 0;
+}
+
+int SoundEngine::enqueue_command(int a, int b, int c, int d, int e, int f, int g) {
+ uint16 *p;
+ uint32 r;
+ uint i;
+
+ i = _queue_pos;
+
+ if (i == _queue_end)
+ return -1;
+
+ if (a==-1) {
+ _queue_adding = false;
+ _trigger_count++;
+ return 0;
+ }
+
+ p = _cmd_queue[_queue_pos].array;
+ p[0] = COMMAND_ID;
+ p[1] = a;
+ p[2] = b;
+ p[3] = c;
+ p[4] = d;
+ p[5] = e;
+ p[6] = f;
+ p[7] = g;
+
+ i = (++i) & (ARRAYSIZE(_cmd_queue)-1);
+
+ if (_queue_end!=i) {
+ _queue_pos = i;
+ return 0;
+ } else {
+ _queue_pos = (--i) & (ARRAYSIZE(_cmd_queue)-1);
+ return -1;
+ }
+}
+
+int SoundEngine::query_queue(int param) {
+ switch(param) {
+ case 0: /* get trigger count */
+ return _trigger_count;
+ case 1: /* get trigger type */
+ if (_queue_end==_queue_pos)
+ return -1;
+ return _cmd_queue[_queue_end].array[1];
+ case 2: /* get trigger sound */
+ if (_queue_end==_queue_pos)
+ return 0xFF;
+ return _cmd_queue[_queue_end].array[2];
+ default:
+ return -1;
+ }
+}
+
+int SoundEngine::set_master_volume(uint vol) {
+ int i;
+ if (vol > 127)
+ return -1;
+ _master_volume = vol;
+ for (i=0; i!=8; i++)
+ _channel_volume_eff[i] = (_channel_volume[i]+1) * vol >> 7;
+ update_volumes();
+ return 0;
+}
+
+int SoundEngine::get_master_volume() {
+ return _master_volume;
+}
+
+int SoundEngine::terminate() {
+ return 0;
+ /* not implemented */
+}
+
+
+int SoundEngine::enqueue_trigger(int sound, int marker) {
+ uint16 *p;
+ uint pos;
+
+ pos = _queue_pos;
+
+ p = _cmd_queue[pos].array;
+ p[0] = TRIGGER_ID;
+ p[1] = sound;
+ p[2] = marker;
+
+ pos = (++pos) & (ARRAYSIZE(_cmd_queue)-1);
+ if (_queue_end==pos) {
+ _queue_pos = (--pos) & (ARRAYSIZE(_cmd_queue)-1);
+ return -1;
+ }
+
+ _queue_pos = pos;
+ _queue_adding = true;
+ _queue_sound = sound;
+ _queue_marker = marker;
+ return 0;
+}
+
+int32 SoundEngine::do_command(int a, int b, int c, int d, int e, int f, int g, int h) {
+ byte cmd = a&0xFF;
+ byte param = a>>8;
+ Player *player;
+
+ if (!_initialized && (cmd || param))
+ return -1;
+
+ if (param==0) {
+ switch(cmd) {
+ case 6:
+ return set_master_volume(b);
+ case 7:
+ return get_master_volume();
+ case 8:
+ return start_sound(b) ? 0 : -1;
+ case 9:
+ return stop_sound(b);
+ case 11:
+ return stop_all_sounds();
+ case 13:
+ return get_sound_status(b);
+ case 16:
+ return set_volchan(b,c);
+ case 17:
+ return set_channel_volume(b,c);
+ case 18:
+ return set_volchan_entry(b,c);
+ default:
+ warning("SoundEngine::do_command invalid command %d", cmd);
+ }
+ } else if (param==1) {
+
+ if ( (1<<cmd) & (0x783FFF)) {
+ player = get_player_byid(b);
+ if (!player)
+ return -1;
+ }
+
+ if ( (1<<cmd) & (1<<11 | 1<<22) ) {
+ assert(c>=0 && c<=15);
+ player = (Player*)player->get_part(c);
+ if(!player)
+ return -1;
+ }
+
+ switch(cmd) {
+ case 0:
+ return player->get_param(c, d);
+ case 1:
+ player->set_priority(c);
+ return 0;
+ case 2:
+ return player->set_vol(c);
+ case 3:
+ player->set_pan(c);
+ return 0;
+ case 4:
+ return player->set_transpose(c, d);
+ case 5:
+ player->set_detune(c);
+ return 0;
+ case 6:
+ player->set_speed(c);
+ return 0;
+ case 7:
+ return player->jump(c,d,e) ? 0 : -1;
+ case 8:
+ return player->scan(c,d,e);
+ case 9:
+ return player->set_loop(c,d,e,f,g) ? 0 : -1;
+ case 10:
+ player->clear_loop();
+ return 0;
+ case 11:
+ ((Part*)player)->set_onoff(d!=0);
+ return 0;
+ case 12:
+ return player->_hook.set(c, d, e);
+ case 13:
+ return player->fade_vol(c,d);
+ case 14:
+ return enqueue_trigger(b,c);
+ case 15:
+ return enqueue_command(b,c,d,e,f,g,h);
+ case 16:
+ return clear_queue();
+ case 19:
+ return player->get_param(c,d);
+ case 20:
+ return player->_hook.set(c,d,e);
+ case 21:
+ return -1;
+ case 22:
+ ((Part*)player)->set_vol(d);
+ return 0;
+ case 23:
+ return query_queue(b);
+ case 24:
+ return 0;
+ default:
+ warning("SoundEngine::do_command default midi command %d", cmd);
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+int SoundEngine::set_channel_volume(uint chan, uint vol) {
+ if (chan>=8 || vol>127)
+ return -1;
+
+ _channel_volume[chan] = vol;
+ _channel_volume_eff[chan] = _master_volume * (vol+1) >> 7;
+ update_volumes();
+ return 0;
+}
+
+void SoundEngine::update_volumes() {
+ Player *player;
+ int i;
+
+ for(i=ARRAYSIZE(_players),player=_players; i!=0; i--,player++) {
+ if (player->_active)
+ player->set_vol(player->_volume);
+ }
+}
+
+int SoundEngine::set_volchan_entry(uint a, uint b) {
+ if (a >= 8)
+ return -1;
+ _volchan_table[a] = b;
+ return 0;
+}
+
+int HookDatas::query_param(int param, byte chan) {
+ switch(param) {
+ case 18:
+ return _jump;
+ case 19:
+ return _transpose;
+ case 20:
+ return _part_onoff[chan];
+ case 21:
+ return _part_volume[chan];
+ case 22:
+ return _part_program[chan];
+ case 23:
+ return _part_transpose[chan];
+ default:
+ return -1;
+ }
+}
+
+int HookDatas::set(byte cls, byte value, byte chan) {
+ switch(cls) {
+ case 0:
+ _jump = value;
+ break;
+ case 1:
+ _transpose = value;
+ break;
+ case 2:
+ if (chan<16)
+ _part_onoff[chan] = value;
+ else if (chan==16)
+ memset(_part_onoff, value, 16);
+ break;
+ case 3:
+ if (chan<16)
+ _part_volume[chan] = value;
+ else if (chan==16)
+ memset(_part_volume, value, 16);
+ break;
+ case 4:
+ if (chan<16)
+ _part_program[chan] = value;
+ else if (chan==16)
+ memset(_part_program, value, 16);
+ break;
+ case 5:
+ if (chan<16)
+ _part_transpose[chan] = value;
+ else if (chan==16)
+ memset(_part_transpose, value, 16);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+
+VolumeFader *SoundEngine::allocate_volume_fader() {
+ VolumeFader *vf;
+ int i;
+
+ vf = _volume_fader;
+ for(i=ARRAYSIZE(_volume_fader); vf->active; ) {
+ vf++;
+ if (!--i)
+ return NULL;
+ }
+
+ vf->active = true;
+ _active_volume_faders = true;
+ return vf;
+}
+
+Player *SoundEngine::get_player_byid(int id) {
+ int i;
+ Player *player,*found=NULL;
+
+ for(i=ARRAYSIZE(_players),player=_players; i!=0; i--,player++) {
+ if (player->_active && player->_id==(uint16)id) {
+ if(found)
+ return NULL;
+ found = player;
+ }
+ }
+ return found;
+}
+
+int SoundEngine::get_volchan_entry(uint a) {
+ if (a<8)
+ return _volchan_table[a];
+ return -1;
+}
+
+int SoundEngine::initialize(Scumm *scumm) {
+ int i;
+ if (_initialized)
+ return -1;
+
+ _s = scumm;
+
+ _master_volume = 127;
+ for (i=0; i!=8; i++)
+ _channel_volume[i] = _channel_volume_eff[i] = _volchan_table[i] = 127;
+
+ init_players();
+ init_sustaining_notes();
+ init_volume_fader();
+ init_queue();
+ init_parts();
+ midiInit();
+
+ _initialized = true;
+
+ return 0;
+}
+
+void SoundEngine::init_queue() {
+ _queue_adding = false;
+ _queue_pos = 0;
+ _queue_end = 0;
+ _trigger_count = 0;
+}
+
+void SoundEngine::pause(bool paused) {
+ Part *part;
+ int i;
+ MidiChannel *mc;
+
+ lock();
+
+ for (i=ARRAYSIZE(_parts),part=_parts; i!=0; i--, part++) {
+ if (part->_player) {
+ if (paused) {
+ part->_vol_eff = 0;
+ } else {
+ part->set_vol(part->_vol);
+ }
+ part->vol_changed();
+ }
+ }
+
+ _paused = paused;
+
+ unlock();
+}
+
+
+/*************************************************************************/
+
+int Player::fade_vol(byte vol, int time) {
+ VolumeFader *vf;
+ int i;
+
+ cancel_volume_fade();
+ if (time==0) {
+ set_vol(vol);
+ return 0;
+ }
+
+ vf = _se->allocate_volume_fader();
+ if (vf==NULL)
+ return -1;
+
+ vf->player = this;
+ vf->num_steps = vf->speed_lo_max = time;
+ vf->curvol = _volume;
+ i = (vol - vf->curvol);
+ vf->speed_hi = i / time;
+ if (i<0) {
+ i = -i;
+ vf->direction = -1;
+ } else {
+ vf->direction = 1;
+ }
+ vf->speed_lo = i % time;
+ vf->speed_lo_counter = 0;
+ return 0;
+}
+
+void Player::clear() {
+ uninit_seq();
+ cancel_volume_fade();
+ uninit_parts();
+ _active = false;
+ _ticks_per_beat = TICKS_PER_BEAT;
+}
+
+bool Player::start_sound(int sound) {
+ void *mdhd;
+
+ mdhd = _se->findTag(sound, MDHD_TAG, 0);
+ if (mdhd==NULL)
+ return false;
+
+ _parts = NULL;
+ _active = true;
+ _id = sound;
+ _priority = 0x80;
+ _volume = 0x7F;
+ _vol_chan = 0xFFFF;
+
+ _vol_eff = (_se->get_channel_volume(0xFFFF)<<7)>>7;
+
+ _pan = 0;
+ _transpose = 0;
+ _detune = 0;
+
+ hook_clear();
+ if (start_seq_sound(sound) != 0) {
+ _active = false;
+ return false;
+ }
+ return true;
+}
+
+void Player::hook_clear() {
+ memset(&_hook, 0, sizeof(_hook));
+}
+
+int Player::start_seq_sound(int sound) {
+ byte *ptr, *track_ptr;
+
+ _song_index = sound;
+ _timer_counter = 0;
+ _loop_to_beat = 1;
+ _loop_from_beat = 1;
+ _track_index = 0;
+ _loop_counter = 0;
+ _loop_to_tick = 0;
+ _loop_from_tick = 0;
+
+ set_tempo(500000);
+ set_speed(128);
+ ptr = _se->findTag(sound, "MTrk", _track_index);
+ if (ptr==NULL)
+ return -1;
+
+ track_ptr = ptr;
+ _cur_pos = _next_pos = get_delta_time(&track_ptr);
+ _song_offset = track_ptr - ptr;
+
+ _tick_index = _cur_pos;
+ _beat_index = 1;
+
+ if (_tick_index >= _ticks_per_beat) {
+ _beat_index += _tick_index/_ticks_per_beat;
+ _tick_index %= _ticks_per_beat;
+ }
+
+ return 0;
+}
+
+void Player::set_tempo(uint32 b) {
+ uint32 i,j;
+
+ i = TEMPO_BASE;
+ j = _tempo = b;
+
+ while (i&0xFFFF0000 || j&0xFFFF0000) { i>>=1; j>>=1; }
+
+ _tempo_eff = (i<<16) / j;
+
+ set_speed(_speed);
+}
+
+void Player::cancel_volume_fade() {
+ VolumeFader *vf = _se->_volume_fader;
+ int i;
+
+ for (i=0; i<8; i++,vf++) {
+ if (vf->active && vf->player==this)
+ vf->active = false;
+ }
+}
+
+void Player::uninit_parts() {
+ if (_parts && _parts->_player != this)
+ error("asd");
+ while(_parts)
+ _parts->uninit();
+}
+
+void Player::uninit_seq() {
+ _abort = true;
+}
+
+void Player::set_speed(byte speed) {
+ _speed = speed;
+ _timer_speed = (_tempo_eff * speed >> 7);
+}
+
+byte *Player::parse_midi(byte *s) {
+ byte cmd,chan,note,velocity,control;
+ uint value;
+ Part *part;
+
+ cmd = *s++;
+
+ chan = cmd&0xF;
+
+ switch(cmd>>4) {
+ case 0x8: /* key off */
+ note = *s++;
+ if (!_scanning) {
+ key_off(chan, note);
+ } else {
+ clear_active_note(chan, note);
+ }
+ s++; /* skip velocity */
+ break;
+
+ case 0x9: /* key on */
+ note = *s++;
+ velocity = *s++;
+ if (velocity) {
+ if (!_scanning)
+ key_on(chan, note,velocity);
+ else
+ set_active_note(chan,note);
+ } else {
+ if (!_scanning)
+ key_off(chan, note);
+ else
+ clear_active_note(chan,note);
+ }
+ break;
+
+ case 0xA: /* aftertouch */
+ s += 2;
+ break;
+
+ case 0xB: /* control change */
+ control = *s++;
+ value = *s++;
+ part = get_part(chan);
+ if (!part)
+ break;
+
+ switch(control) {
+ case 1: /* modulation wheel */
+ part->set_modwheel(value);
+ break;
+ case 7: /* volume */
+ part->set_vol(value);
+ break;
+ case 10: /* pan position */
+ part->set_pan(value - 0x40);
+ break;
+ case 16: /* pitchbend factor */
+ part->set_pitchbend_factor(value);
+ break;
+ case 17: /* gp slider 2 */
+ part->set_detune(value - 0x40);
+ break;
+ case 18: /* gp slider 3 */
+ part->set_pri(value - 0x40, true);
+ break;
+ case 64: /* hold pedal */
+ part->set_pedal(value!=0);
+ break;
+ case 91: /* effects level */
+ part->set_effect_level(value);
+ break;
+ case 93: /* chorus */
+ part->set_chorus(value);
+ break;
+ default:
+ warning("parse_midi: invalid control %d", control);
+ }
+ break;
+
+ case 0xC: /* program change */
+ value = *s++;
+ part = get_part(chan);
+ if (part)
+ part->set_program(value);
+ break;
+
+ case 0xD: /* channel pressure */
+ s++;
+ break;
+
+ case 0xE: /* pitch bend */
+ part = get_part(chan);
+ if (part)
+ part->set_pitchbend(((s[1]-0x40)<<7)|s[0]);
+ s+=2;
+ break;
+
+ case 0xF:
+ if (chan==0) {
+ uint size = get_delta_time(&s);
+ if (*s==SYSEX_ID)
+ parse_sysex(s,size);
+ s += size;
+ } else if (chan==0xF) {
+ cmd = *s++;
+ if (cmd==47)
+ goto Error; /* end of song */
+ if (cmd==81) {
+ set_tempo((s[1]<<16) | (s[2]<<8) | s[3]);
+ s+=4;
+ break;
+ }
+ s += get_delta_time(&s);
+ } else if (chan==0x7) {
+ s += get_delta_time(&s);
+ } else {
+ goto Error;
+ }
+ break;
+
+ default:
+Error:;
+ if(!_scanning)
+ clear();
+ return NULL;
+ }
+ return s;
+}
+
+void Player::parse_sysex(byte *p, uint len) {
+ byte code;
+ byte a;
+ uint b;
+ byte buf[128];
+ Part *part;
+
+ /* too big? */
+ if (len>=sizeof(buf)*2)
+ return;
+
+ /* skip sysex manufacturer */
+ p++;
+ len -= 2;
+
+ switch(code=*p++) {
+ case 16:
+ a = *p++ & 0x0F;
+ if (HARDWARE_TYPE != *p++)
+ break;
+ decode_sysex_bytes(p, buf, len - 3);
+ part = get_part(a);
+ if(part)
+ part->set_instrument(buf);
+ break;
+
+ case 17:
+ p++;
+ if (HARDWARE_TYPE != *p++)
+ break;
+ a=*p++;
+ decode_sysex_bytes(p, buf, len - 4);
+ _se->set_instrument(a, buf);
+ break;
+
+ case 33: /* param adjust */
+ a = *p++ & 0x0F;
+ if (HARDWARE_TYPE != *p++)
+ break;
+ decode_sysex_bytes(p, buf, len - 3);
+ part = get_part(a);
+ if (part)
+ part->set_chan_param(read_word(buf),read_word(buf+2));
+ break;
+
+ case 48: /* hook - jump */
+ if (_scanning)
+ break;
+ decode_sysex_bytes(p+1,buf,len-2);
+ maybe_jump(buf);
+ break;
+
+ case 49: /* hook - global transpose */
+ decode_sysex_bytes(p+1,buf,len-2);
+ maybe_set_transpose(buf);
+ break;
+
+ case 50: /* hook - part on/off */
+ buf[0] = *p++ & 0x0F;
+ decode_sysex_bytes(p,buf+1,len-2);
+ maybe_part_onoff(buf);
+ break;
+
+ case 51: /* hook - set volume */
+ buf[0] = *p++ & 0x0F;
+ decode_sysex_bytes(p,buf+1,len-2);
+ maybe_set_volume(buf);
+ break;
+
+ case 52: /* hook - set program */
+ buf[0] = *p++ & 0x0F;
+ decode_sysex_bytes(p,buf+1,len-2);
+ maybe_set_program(buf);
+ break;
+
+ case 53: /* hook - set transpose */
+ buf[0] = *p++ & 0x0F;
+ decode_sysex_bytes(p,buf+1,len-2);
+ maybe_set_transpose_part(buf);
+ break;
+
+ case 64: /* marker */
+ p++;
+ len -= 2;
+ while (len--) {
+ _se->handle_marker(_id, *p++);
+ }
+ break;
+
+ case 80: /* loop */
+ decode_sysex_bytes(p+1,buf,len-2);
+ set_loop(
+ read_word(buf),
+ read_word(buf+2),
+ read_word(buf+4),
+ read_word(buf+6),
+ read_word(buf+8)
+ );
+ break;
+
+ case 81: /* end loop */
+ clear_loop();
+ break;
+
+ case 96: /* set instrument */
+ part = get_part(p[0] & 0x0F);
+ b = (p[1]&0x0F)<<12 | (p[2]&0x0F)<<8 | (p[4]&0x0F)<<4 | (p[4]&0x0F);
+ if(part)
+ part->set_instrument(b);
+ break;
+
+ default:
+ debug(6,"unknown sysex %d", code);
+ }
+}
+
+void Player::decode_sysex_bytes(byte *src, byte *dst, int len) {
+ while(len>=0) {
+ *dst++ = (src[0]<<4)|(src[1]&0xF);
+ src += 2;
+ len -= 2;
+ }
+}
+
+void Player::maybe_jump(byte *data) {
+ byte cmd;
+
+ cmd = data[0];
+
+ /* is this the hook i'm waiting for? */
+ if (cmd && _hook._jump!=cmd)
+ return;
+
+ /* reset hook? */
+ if(cmd!=0 && cmd<0x80)
+ _hook._jump = 0;
+
+ jump(read_word(data+1), read_word(data+3), read_word(data+5));
+}
+
+void Player::maybe_set_transpose(byte *data) {
+ byte cmd;
+
+ cmd = data[0];
+
+ /* is this the hook i'm waiting for? */
+ if (cmd && _hook._transpose!=cmd)
+ return;
+
+ /* reset hook? */
+ if(cmd!=0 && cmd<0x80)
+ _hook._transpose = 0;
+
+ set_transpose(data[1], (int8)data[2]);
+}
+
+void Player::maybe_part_onoff(byte *data) {
+ byte cmd,*p;
+ uint chan;
+ Part *part;
+
+ cmd = data[1];
+ chan = data[0];
+
+ p = &_hook._part_onoff[chan];
+
+ /* is this the hook i'm waiting for? */
+ if (cmd && *p!=cmd)
+ return;
+
+ if (cmd!=0 && cmd<0x80)
+ *p = 0;
+
+ part = get_part(chan);
+ if (part)
+ part->set_onoff(data[2]!=0);
+}
+
+void Player::maybe_set_volume(byte *data) {
+ byte cmd;
+ byte *p;
+ uint chan;
+ Part *part;
+
+ cmd = data[1];
+ chan = data[0];
+
+ p = &_hook._part_volume[chan];
+
+ /* is this the hook i'm waiting for? */
+ if (cmd && *p!=cmd)
+ return;
+
+ /* reset hook? */
+ if (cmd!=0 && cmd<0x80)
+ *p = 0;
+
+ part = get_part(chan);
+ if (part)
+ part->set_vol(data[2]);
+}
+
+void Player::maybe_set_program(byte *data) {
+ byte cmd;
+ byte *p;
+ uint chan;
+ Part *part;
+
+ cmd = data[1];
+ chan = data[0];
+
+ /* is this the hook i'm waiting for? */
+ p = &_hook._part_program[chan];
+
+ if (cmd && *p!=cmd)
+ return;
+
+ if (cmd!=0 && cmd<0x80)
+ *p = 0;
+
+ part = get_part(chan);
+ if (part)
+ part->set_program(data[2]);
+}
+
+void Player::maybe_set_transpose_part(byte *data) {
+ byte cmd;
+ byte *p;
+ uint chan;
+
+ cmd = data[1];
+ chan = data[0];
+
+ /* is this the hook i'm waiting for? */
+ p = &_hook._part_transpose[chan];
+
+ if (cmd && *p!=cmd)
+ return;
+
+ /* reset hook? */
+ if (cmd!=0 && cmd<0x80)
+ *p = 0;
+
+ part_set_transpose(chan, data[2], (int8)data[3]);
+}
+
+int Player::set_transpose(byte relative, int b) {
+ Part *part;
+
+ if (b>24 || b<-24 || relative>1)
+ return -1;
+ if (relative)
+ b = transpose_clamp(_transpose + b, -7, 7);
+
+ _transpose = b;
+
+ for(part=_parts; part; part=part->_next) {
+ part->set_transpose(part->_transpose);
+ }
+
+ return 0;
+}
+
+void Player::clear_active_notes() {
+ memset(_se->_active_notes, 0, sizeof(_se->_active_notes));
+}
+
+void Player::clear_active_note(int chan, byte note) {
+ _se->_active_notes[note] &= ~(1<<chan);
+}
+
+void Player::set_active_note(int chan, byte note) {
+ _se->_active_notes[note] |= (1<<chan);
+}
+
+void Player::part_set_transpose(uint8 chan, byte relative, int8 b) {
+ Part *part;
+
+ if (b>24 || b<-24)
+ return;
+
+ part = get_part(chan);
+ if (!part)
+ return;
+ if (relative)
+ b = transpose_clamp(b + part->_transpose, -7, 7);
+ part->set_transpose(b);
+}
+
+void Player::key_on(uint8 chan, uint8 note, uint8 velocity) {
+ Part *part;
+
+ part = get_part(chan);
+ if (!part || !part->_on)
+ return;
+
+ part->key_on(note, velocity);
+}
+
+void Player::key_off(uint8 chan, uint8 note) {
+ Part *part;
+
+ for(part=_parts; part; part = part->_next) {
+ if (part->_chan==(byte)chan && part->_on)
+ part->key_off(note);
+ }
+}
+
+bool Player::jump(uint track, uint beat, uint tick) {
+ byte *mtrk, *cur_mtrk, *scanpos;
+ uint32 topos,curpos,track_offs;
+
+ if (!_active)
+ return false;
+
+ mtrk = _se->findTag(_song_index, "MTrk", track);
+ if (!mtrk)
+ return false;
+
+ cur_mtrk = _se->findTag(_song_index,"MTrk", _track_index);
+ if (!cur_mtrk)
+ return false;
+
+ _se->lock();
+
+ if (beat==0)
+ beat=1;
+
+ topos = (beat-1) * _ticks_per_beat + tick;
+
+ if (track == _track_index && topos >= _cur_pos) {
+ scanpos = _song_offset + mtrk;
+ curpos = _next_pos;
+ } else {
+ scanpos = mtrk;
+ curpos = get_delta_time(&scanpos);
+ }
+
+ while (curpos < topos) {
+ skip_midi_cmd(&scanpos);
+ if (!scanpos) {
+ _se->unlock();
+ return false;
+ }
+ curpos += get_delta_time(&scanpos);
+ }
+
+ track_offs = scanpos - mtrk;
+
+ turn_off_pedals();
+
+ find_sustaining_notes(cur_mtrk+_song_offset, mtrk+track_offs, curpos-topos);
+
+ _beat_index = beat;
+ _tick_index = tick;
+ _cur_pos = topos;
+ _next_pos = curpos;
+ _timer_counter = 0;
+ _song_offset = track_offs;
+ if (track != _track_index) {
+ _track_index = track;
+ _loop_counter = 0;
+ }
+ _abort = true;
+ _se->unlock();
+ return true;
+}
+
+bool Player::set_loop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick) {
+ if (tobeat+1 >= frombeat)
+ return false;
+
+ if (tobeat==0)
+ tobeat=1;
+
+ _loop_counter = 0; /* because of possible interrupts */
+ _loop_to_beat = tobeat;
+ _loop_to_tick = totick;
+ _loop_from_beat = frombeat;
+ _loop_from_tick = fromtick;
+ _loop_counter = count;
+
+ return true;
+}
+
+void Player::clear_loop() {
+ _loop_counter = 0;
+}
+
+void Player::turn_off_pedals() {
+ Part *part;
+
+ for(part=_parts; part; part = part->_next) {
+ if (part->_pedal)
+ part->set_pedal(false);
+ }
+}
+
+void Player::find_sustaining_notes(byte *a, byte *b, uint32 l) {
+ uint32 pos;
+ uint16 mask;
+ uint16 *bitlist_ptr;
+ SustainingNotes *sn,*next;
+ IsNoteCmdData isnote;
+ int j;
+ uint num_active;
+ uint max_off_pos;
+
+ num_active = update_actives();
+
+ /* pos contains number of ticks since current position */
+ pos = _next_pos - _cur_pos;
+ if ((int32)pos<0)
+ pos = 0;
+
+ /* locate the positions where the notes are turned off.
+ * remember each note that was turned off
+ */
+ while (num_active != 0) {
+ /* is note off? */
+ j = is_note_cmd(&a,&isnote);
+ if (j==-1)
+ break;
+ if (j == 1) {
+ mask = 1<<isnote.chan;
+ bitlist_ptr = _se->_active_notes + isnote.note;
+ if (*bitlist_ptr & mask) {
+ *bitlist_ptr &= ~mask;
+ num_active--;
+ /* Get a node from the free list */
+ if ((sn=_se->_sustain_notes_free) == NULL)
+ return;
+ _se->_sustain_notes_free = sn->next;
+
+ /* Insert it in the beginning of the used list */
+ sn->next = _se->_sustain_notes_used;
+ _se->_sustain_notes_used = sn;
+ sn->prev = NULL;
+ if (sn->next)
+ sn->next->prev = sn;
+
+ sn->note = isnote.note;
+ sn->chan = isnote.chan;
+ sn->player = this;
+ sn->off_pos = pos;
+ sn->pos = 0;
+ sn->counter = 0;
+ }
+ }
+ pos += get_delta_time(&a);
+ }
+
+ /* find the maximum position where a note was turned off */
+ max_off_pos = 0;
+ for(sn=_se->_sustain_notes_used; sn; sn = sn->next) {
+ _se->_active_notes[sn->note] |= (1<<sn->chan);
+ if (sn->off_pos > max_off_pos) {
+ max_off_pos = sn->off_pos;
+ }
+ }
+
+ /* locate positions where notes are turned on */
+ pos = l;
+ while (pos < max_off_pos) {
+ j = is_note_cmd(&b,&isnote);
+ if (j==-1)
+ break;
+ if (j == 2) {
+ mask = 1<<isnote.chan;
+ bitlist_ptr = _se->_active_notes + isnote.note;
+
+ if (*bitlist_ptr&mask) {
+ sn = _se->_sustain_notes_used;
+ while (sn) {
+ next = sn->next;
+ if (sn->note==isnote.note && sn->chan==isnote.chan && pos < sn->off_pos) {
+ *bitlist_ptr &= ~mask;
+ /* Unlink from the sustain list */
+ if (next)
+ next->prev = sn->prev;
+ if (sn->prev)
+ sn->prev->next = next;
+ else
+ _se->_sustain_notes_used = next;
+ /* Insert into the free list */
+ sn->next = _se->_sustain_notes_free;
+ _se->_sustain_notes_free = sn;
+ }
+ sn = next;
+ }
+ }
+ }
+ pos += get_delta_time(&b);
+ }
+
+ /* Concatenate head and used list */
+ if (!_se->_sustain_notes_head) {
+ _se->_sustain_notes_head = _se->_sustain_notes_used;
+ _se->_sustain_notes_used = NULL;
+ return;
+ }
+ sn = _se->_sustain_notes_head;
+ while (sn->next) sn = sn->next;
+ sn->next = _se->_sustain_notes_used;
+ _se->_sustain_notes_used = NULL;
+ if (sn->next)
+ sn->next->prev = sn;
+}
+
+Part *Player::get_part(uint8 chan) {
+ Part *part;
+
+ part = _parts;
+ while (part) {
+ if (part->_chan == chan)
+ return part;
+ part = part->_next;
+ }
+
+ part = _se->allocate_part(_priority);
+ if (!part) {
+ warning("no parts available");
+ return NULL;
+ }
+
+ part->_chan = chan;
+ part->setup(this);
+
+ return part;
+}
+
+uint Player::update_actives() {
+ Part *part;
+ MidiChannel *mc;
+ uint16 *active;
+ int count = 0;
+
+ clear_active_notes();
+ active = _se->_active_notes;
+ for(part=_parts; part; part = part->_next) {
+ if (part->_mc)
+ count += part->update_actives(active);
+ }
+ return count;
+}
+
+void Player::set_priority(int pri) {
+ Part *part;
+
+ _priority = pri;
+ for(part=_parts; part; part = part->_next) {
+ part->set_pri(part->_pri, false);
+ }
+ _se->adjust_priorities();
+}
+
+void Player::set_pan(int pan) {
+ Part *part;
+
+ _pan = pan;
+ for(part=_parts; part; part = part->_next) {
+ part->set_pan(part->_pan);
+ }
+}
+
+void Player::set_detune(int detune) {
+ Part *part;
+
+ _detune = detune;
+ for(part=_parts; part; part = part->_next) {
+ part->set_detune(part->_detune);
+ }
+}
+
+int Player::scan(uint totrack, uint tobeat, uint totick) {
+ byte *mtrk,*scanptr;
+ uint32 curpos,topos;
+ uint32 pos;
+
+ assert(totrack>=0 && tobeat>=0 && totick>=0);
+
+ if (!_active)
+ return -1;
+
+ mtrk = _se->findTag(_song_index, "MTrk", totrack);
+ if (!mtrk)
+ return -1;
+
+ _se->lock();
+ if (tobeat==0)
+ tobeat++;
+
+ silence_parts();
+ clear_active_notes();
+ scanptr = mtrk;
+ curpos = get_delta_time(&scanptr);
+ _scanning=true;
+
+ topos = (tobeat-1) * _ticks_per_beat + totick;
+
+ while (curpos < topos) {
+ scanptr = parse_midi(scanptr);
+ if (!scanptr) {
+ _scanning=false;
+ _se->unlock();
+ return -1;
+ }
+ curpos += get_delta_time(&scanptr);
+ }
+ pos = scanptr - mtrk;
+
+ _scanning=false;
+ play_active_notes();
+ _beat_index = tobeat;
+ _tick_index = totick;
+ _cur_pos = topos;
+ _next_pos = curpos;
+ _timer_counter = 0;
+ _song_offset = pos;
+ if (_track_index != totrack) {
+ _track_index = totrack;
+ _loop_counter = 0;
+ }
+ _se->unlock();
+ return 0;
+}
+
+void Player::silence_parts() {
+ Part *part;
+
+ for(part=_parts; part; part = part->_next)
+ if (part->_mc)
+ part->silence();
+}
+
+void Player::play_active_notes() {
+ int i,j;
+ uint mask;
+
+ for (i=0; i!=128; i++) {
+ mask = _se->_active_notes[i];
+ for (j=0; j!=16; j++,mask>>=1) {
+ if (mask&1) {
+ key_on(j, i, 80);
+ }
+ }
+ }
+}
+
+int Player::set_vol(byte vol) {
+ Part *part;
+
+ if (vol > 127)
+ return -1;
+
+ _volume = vol;
+ _vol_eff = _se->get_channel_volume(_vol_chan) * (vol + 1) >> 7;
+
+ for(part=_parts; part; part=part->_next) {
+ part->set_vol(part->_vol);
+ }
+
+ return 0;
+}
+
+int Player::get_param(int param, byte chan) {
+ switch(param) {
+ case 0:
+ return (byte)_priority;
+ case 1:
+ return (byte)_volume;
+ case 2:
+ return (byte)_pan;
+ case 3:
+ return (byte)_transpose;
+ case 4:
+ return (byte)_detune;
+ case 5:
+ return _speed;
+ case 6:
+ return _track_index;
+ case 7:
+ return _beat_index;
+ case 8:
+ return _tick_index;
+ case 9:
+ return _loop_counter;
+ case 10:
+ return _loop_to_beat;
+ case 11:
+ return _loop_to_tick;
+ case 12:
+ return _loop_from_beat;
+ case 13:
+ return _loop_from_tick;
+ case 14: case 15: case 16: case 17:
+ return query_part_param(param, chan);
+ case 18: case 19: case 20: case 21: case 22: case 23:
+ return _hook.query_param(param, chan);
+ default:
+ return -1;
+ }
+}
+
+int Player::query_part_param(int param, byte chan) {
+ Part *part;
+
+ part = _parts;
+ while (part) {
+ if(part->_chan==chan) {
+ switch(param) {
+ case 14:
+ return part->_on;
+ case 15:
+ return part->_vol;
+ case 16:
+ return part->_program;
+ case 17:
+ return part->_transpose;
+ default:
+ return -1;
+ }
+ }
+ part = part->_next;
+ }
+ return 129;
+}
+
+/*******************************************************************/
+
+#define OFFS(type,item) ((int)(&((type*)0)->item))
+#define SIZE(type,item) sizeof(((type*)0)->item)
+#define MKLINE(type,item,saveas) {OFFS(type,item),saveas,SIZE(type,item)}
+#define MKARRAY(type,item,saveas,num) {OFFS(type,item),128|saveas,SIZE(type,item)}, {num,0,0}
+#define MKEND() {0xFFFF,0xFF,0xFF}
+
+#define MKREF(type,item,refid) {OFFS(type,item),refid,0xFF}
+
+enum {
+ TYPE_PART = 1,
+ TYPE_PLAYER = 2,
+};
+
+int SoundEngine::saveReference(SoundEngine *me, byte type, void*ref) {
+ switch(type) {
+ case TYPE_PART: return (Part*)ref - me->_parts;
+ case TYPE_PLAYER: return (Player*)ref - me->_players;
+ default:
+ error("saveReference: invalid type");
+ }
+}
+
+void *SoundEngine::loadReference(SoundEngine *me, byte type, int ref) {
+ switch(type) {
+ case TYPE_PART: return &me->_parts[ref];
+ case TYPE_PLAYER: return &me->_players[ref];
+ default:
+ error("loadReference: invalid type");
+ }
+}
+
+int SoundEngine::save_or_load(Serializer *ser) {
+ const SaveLoadEntry mainEntries[] = {
+ MKLINE(SoundEngine,_queue_end, sleUint8),
+ MKLINE(SoundEngine,_queue_pos, sleUint8),
+ MKLINE(SoundEngine,_queue_sound, sleUint16),
+ MKLINE(SoundEngine,_queue_adding, sleByte),
+ MKLINE(SoundEngine,_queue_marker, sleByte),
+ MKLINE(SoundEngine,_queue_cleared, sleByte),
+ MKLINE(SoundEngine,_master_volume, sleByte),
+ MKLINE(SoundEngine,_trigger_count, sleUint16),
+ MKARRAY(SoundEngine,_channel_volume[0], sleUint16, 8),
+ MKARRAY(SoundEngine,_volchan_table[0], sleUint16, 8),
+ MKEND()
+ };
+
+ const SaveLoadEntry playerEntries[] = {
+ MKREF(Player,_parts,TYPE_PART),
+ MKLINE(Player,_active,sleByte),
+ MKLINE(Player,_id,sleUint16),
+ MKLINE(Player,_priority,sleByte),
+ MKLINE(Player,_volume,sleByte),
+ MKLINE(Player,_pan,sleInt8),
+ MKLINE(Player,_transpose,sleByte),
+ MKLINE(Player,_detune,sleInt8),
+ MKLINE(Player,_vol_chan,sleUint16),
+ MKLINE(Player,_vol_eff,sleByte),
+ MKLINE(Player,_speed,sleByte),
+ MKLINE(Player,_song_index,sleUint16),
+ MKLINE(Player,_track_index,sleUint16),
+ MKLINE(Player,_timer_counter,sleUint16),
+ MKLINE(Player,_loop_to_beat,sleUint16),
+ MKLINE(Player,_loop_from_beat,sleUint16),
+ MKLINE(Player,_loop_counter,sleUint16),
+ MKLINE(Player,_loop_to_tick,sleUint16),
+ MKLINE(Player,_loop_from_tick,sleUint16),
+ MKLINE(Player,_tempo,sleUint32),
+ MKLINE(Player,_cur_pos,sleUint32),
+ MKLINE(Player,_next_pos,sleUint32),
+ MKLINE(Player,_song_offset,sleUint32),
+ MKLINE(Player,_tick_index,sleUint16),
+ MKLINE(Player,_beat_index,sleUint16),
+ MKLINE(Player,_ticks_per_beat,sleUint16),
+ MKLINE(Player,_hook._jump,sleByte),
+ MKLINE(Player,_hook._transpose,sleByte),
+ MKARRAY(Player,_hook._part_onoff[0],sleByte,16),
+ MKARRAY(Player,_hook._part_volume[0],sleByte,16),
+ MKARRAY(Player,_hook._part_program[0],sleByte,16),
+ MKARRAY(Player,_hook._part_transpose[0],sleByte,16),
+ MKEND()
+ };
+
+ const SaveLoadEntry volumeFaderEntries[] = {
+ MKREF(VolumeFader,player,TYPE_PLAYER),
+ MKLINE(VolumeFader,active,sleUint8),
+ MKLINE(VolumeFader,curvol,sleUint8),
+ MKLINE(VolumeFader,speed_lo_max,sleUint16),
+ MKLINE(VolumeFader,num_steps,sleUint16),
+ MKLINE(VolumeFader,speed_hi,sleInt8),
+ MKLINE(VolumeFader,direction,sleInt8),
+ MKLINE(VolumeFader,speed_lo,sleInt8),
+ MKLINE(VolumeFader,speed_lo_counter,sleUint16),
+ MKEND()
+ };
+
+ const SaveLoadEntry partEntries[] = {
+ MKREF(Part,_next,TYPE_PART),
+ MKREF(Part,_prev,TYPE_PART),
+ MKREF(Part,_player,TYPE_PLAYER),
+ MKLINE(Part,_pitchbend,sleInt16),
+ MKLINE(Part,_pitchbend_factor,sleUint8),
+ MKLINE(Part,_transpose,sleInt8),
+ MKLINE(Part,_vol,sleUint8),
+ MKLINE(Part,_detune,sleInt8),
+ MKLINE(Part,_pan,sleInt8),
+ MKLINE(Part,_on,sleUint8),
+ MKLINE(Part,_modwheel,sleUint8),
+ MKLINE(Part,_pedal,sleUint8),
+ MKLINE(Part,_program,sleUint8),
+ MKLINE(Part,_pri,sleUint8),
+ MKLINE(Part,_chan,sleUint8),
+ MKLINE(Part,_effect_level,sleUint8),
+ MKLINE(Part,_chorus,sleUint8),
+ MKLINE(Part,_gmidi_5,sleUint8),
+ MKLINE(Part,_gmidi_1,sleUint8),
+ MKEND()
+ };
+
+ if (!ser->isSaving()) {
+ stop_all_sounds();
+ }
+
+ ser->_ref_me = this;
+ ser->_saveload_ref = ser->isSaving() ? ((void*)&saveReference) : ((void*)&loadReference);
+
+ ser->saveLoadEntries(this, mainEntries);
+ ser->saveLoadArrayOf(_players, ARRAYSIZE(_players), sizeof(_players[0]), playerEntries);
+ ser->saveLoadArrayOf(_parts, ARRAYSIZE(_parts),sizeof(_parts[0]), partEntries);
+ ser->saveLoadArrayOf(_volume_fader,ARRAYSIZE(_volume_fader),
+ sizeof(_volume_fader[0]), volumeFaderEntries);
+
+ if (!ser->isSaving()) {
+ /* Load all sounds that we need */
+ int i;
+ fix_players_after_load();
+ init_sustaining_notes();
+ _active_volume_faders = true;
+ fix_parts_after_load();
+ adjust_priorities();
+ }
+
+ return 0;
+}
+
+void SoundEngine::fix_parts_after_load() {
+ Part *part;
+ int i;
+
+ for (i=ARRAYSIZE(_parts),part=_parts; i!=0; i--, part++) {
+ if (part->_player)
+ part->fix_after_load();
+ }
+}
+
+void SoundEngine::fix_players_after_load() {
+ Player *player = _players;
+ int i;
+
+ for (i=ARRAYSIZE(_players); i!=0; i--, player++) {
+ if (player->_active) {
+ player->set_tempo(player->_tempo);
+ _s->getResourceAddress(rtSound, player->_id);
+ }
+ }
+}
+
+void Part::fix_after_load() {
+ set_transpose(_transpose);
+ set_vol(_vol);
+ set_detune(_detune);
+ set_pri(_pri,false);
+ set_pan(_pan);
+}
+
+void Part::key_on(byte note, byte velocity) {
+ if (_mc) {
+ _mc->_actives[note>>4] |= (1<<(note&0xF));
+ _se->midiNoteOn(_mc->_chan, note, velocity);
+ } else if (_gmidi_5) {
+ _se->midiVolume(SPECIAL_CHANNEL, _vol_eff);
+ _se->midiProgram(SPECIAL_CHANNEL, _gmidi_1);
+ _se->midiNoteOn(SPECIAL_CHANNEL, note, velocity);
+ }
+}
+
+void Part::key_off(byte note) {
+ if (_mc) {
+ _mc->_actives[note>>4] &= ~(1<<(note&0xF));
+ _se->midiNoteOff(_mc->_chan, note);
+ } else if (_gmidi_5) {
+ _se->midiNoteOff(SPECIAL_CHANNEL, note);
+ }
+}
+
+void Part::init(SoundEngine *se) {
+ _se = se;
+ _player = NULL;
+ _next = NULL;
+ _prev = NULL;
+ _mc = NULL;
+}
+
+void Part::setup(Player *player) {
+ _player = player;
+
+ /* Insert first into player's list */
+ _prev = NULL;
+ _next = player->_parts;
+ if (player->_parts)
+ player->_parts->_prev = this;
+ player->_parts = this;
+
+ _gmidi_5 = true;
+ _on = true;
+ _pri_eff = player->_priority;
+ _pri = 0;
+ _vol = 127;
+ _vol_eff = player->_vol_eff;
+ _pan = clamp(player->_pan, -64, 63);
+ _transpose_eff = player->_transpose;
+ _transpose = 0;
+ _detune = 0;
+ _detune_eff = player->_detune;
+ _pitchbend_factor = 2;
+ _pitchbend = 0;
+ _effect_level = 64;
+ _program = 255;
+ _chorus = 0;
+ _modwheel = 0;
+ _gmidi_1 = 0;
+ _pedal = false;
+ _mc = NULL;
+}
+
+void Part::uninit() {
+ if (!_player)
+ return;
+ off();
+
+ /* unlink */
+ if (_next)
+ _next->_prev = _prev;
+ if (_prev)
+ _prev->_next = _next;
+ else
+ _player->_parts = _next;
+ _player = NULL;
+ _next = NULL;
+ _prev = NULL;
+}
+
+void Part::off() {
+ if (_mc) {
+ silence();
+ _mc->_part = NULL;
+ _mc = NULL;
+ }
+}
+
+void Part::silence() {
+ memset(_mc->_actives, 0, sizeof(_mc->_actives));
+ _se->midiSilence(_mc->_chan);
+}
+
+void Part::set_detune(int8 detune) {
+ _detune_eff = clamp((_detune=detune) + _player->_detune, -128, 127);
+ mod_changed();
+}
+
+void Part::set_pitchbend(int value) {
+ _pitchbend = value * _pitchbend_factor >> 6;
+ mod_changed();
+}
+
+void Part::set_vol(uint8 vol) {
+ _vol_eff = ((_vol=vol)+1)*_player->_vol_eff >> 7;
+ vol_changed();
+}
+
+void Part::set_pri(int8 pri, bool recalc) {
+ _pri_eff = clamp((_pri=pri) + _player->_priority, 0, 255);
+ if (recalc)
+ _se->adjust_priorities();
+}
+
+void Part::set_pan(int8 pan) {
+ _pan_eff = clamp((_pan=pan) + _player->_pan, -64, 63);
+ pan_changed();
+}
+
+void Part::set_transpose(int8 transpose) {
+ _transpose_eff = transpose_clamp((_transpose=transpose) +
+ _player->_transpose, -12, 12);
+ mod_changed();
+}
+
+void Part::set_pedal(bool value) {
+ _pedal = value;
+ pedal_changed();
+}
+
+void Part::set_modwheel(uint value) {
+ _modwheel = value;
+ modwheel_changed();
+}
+
+void Part::set_chorus(uint chorus) {
+ _chorus = chorus;
+ chorus_changed();
+}
+
+void Part::set_effect_level(uint level) {
+ _effect_level = level;
+ effect_level_changed();
+}
+
+void Part::set_program(byte program) {
+ if (_program!=program || _gmidi_1!=0) {
+ _program = program;
+ _gmidi_1 = 0;
+ program_changed();
+ if (_gmidi_5) {
+ _gmidi_5 = false;
+ _se->adjust_priorities();
+ }
+ }
+}
+
+void Part::set_instrument(uint b) {
+ _gmidi_1 = (byte)(b>>8);
+ _program = (byte)b;
+
+ if (_program < 128) {
+ program_changed();
+ if(_gmidi_5) {
+ _gmidi_5 = false;
+ _se->adjust_priorities();
+ }
+ }
+}
+
+void Part::set_pitchbend_factor(uint8 value) {
+ if (value > 12)
+ return;
+ set_pitchbend(0);
+ _pitchbend_factor = value;
+}
+
+void Part::set_onoff(bool on) {
+ if (_on != on) {
+ _on = on;
+ if (!on)
+ off();
+ if (!_gmidi_5)
+ _se->adjust_priorities();
+ }
+}
+
+void Part::mod_changed() {
+ if (_mc) {
+ _se->midiPitchBend(_mc->_chan, clamp(_pitchbend + _detune_eff + (_transpose_eff<<7), -2048, 2047));
+ }
+}
+
+void Part::vol_changed() {
+ if (_mc) {
+ _se->midiVolume(_mc->_chan, _vol_eff);
+ }
+}
+
+void Part::pedal_changed() {
+ if (_mc) {
+ _se->midiPedal(_mc->_chan, _pedal);
+ }
+}
+
+void Part::modwheel_changed() {
+ if (_mc) {
+ _se->midiModWheel(_mc->_chan, _modwheel);
+ }
+}
+
+void Part::effect_level_changed() {
+ if (_mc) {
+ _se->midiEffectLevel(_mc->_chan, _effect_level);
+ }
+}
+
+void Part::chorus_changed() {
+ if (_mc) {
+ _se->midiChorus(_mc->_chan, _effect_level);
+ }
+}
+
+void Part::program_changed() {
+ if (_mc) {
+ if (_gmidi_1) {
+ _se->midiControl0(_mc->_chan, _gmidi_1);
+ _se->midiProgram(_mc->_chan, _program);
+ _se->midiControl0(_mc->_chan, 0);
+ } else {
+ _se->midiProgram(_mc->_chan, _program);
+ }
+ }
+}
+
+void Part::pan_changed() {
+ if (_mc) {
+ _se->midiPan(_mc->_chan, _pan_eff);
+ }
+}
+
+int Part::update_actives(uint16 *active) {
+ int i,j;
+ uint16 *act,mask,bits;
+ int count = 0;
+
+ bits = 1<<_chan;
+
+ act = _mc->_actives;
+
+ for(i=8; i; i--) {
+ mask = *act++;
+ if (mask) {
+ for(j=16; j; j--,mask>>=1,active++) {
+ if (mask&1 && !(*active&bits)) {
+ *active|=bits;
+ count++;
+ }
+ }
+ } else {
+ active += 16;
+ }
+ }
+ return count;
+}
+
+void MidiChannel::init(byte chan) {
+ int i;
+
+ _part = NULL;
+ _chan = chan;
+
+ memset(_actives, 0, sizeof(_actives));
+}
+
+void SoundEngine::lock() {
+ _locked++;
+}
+
+void SoundEngine::unlock() {
+ _locked--;
+}
+
+
+void SoundEngine::adjust_priorities() {
+ Part *part,*hipart;
+ int i;
+ byte hipri,lopri;
+ MidiChannel *mc,*lomc;
+
+ while(true) {
+ hipri = 0;
+ hipart = NULL;
+ for(i=32,part=_parts; i; i--,part++) {
+ if (part->_player && part->_gmidi_5==0 && part->_on && !part->_mc && part->_pri_eff>=hipri) {
+ hipri = part->_pri_eff;
+ hipart = part;
+ }
+ }
+
+ if (!hipart)
+ return;
+
+ lopri = 255;
+ lomc = NULL;
+ for(i=ARRAYSIZE(_midi_channels),mc=_midi_channels;;mc++) {
+ if (!mc->_part) {
+ lomc = mc;
+ break;
+ }
+ if (mc->_part->_pri_eff<=lopri) {
+ lopri = mc->_part->_pri_eff;
+ lomc = mc;
+ }
+
+ if (!--i) {
+ if (lopri >= hipri)
+ return;
+ lomc->_part->off();
+ break;
+ }
+ }
+
+ hipart->_mc = lomc;
+ lomc->_part = hipart;
+ hipart->vol_changed();
+ hipart->pan_changed();
+ hipart->mod_changed();
+ hipart->modwheel_changed();
+ hipart->pedal_changed();
+ hipart->effect_level_changed();
+ hipart->program_changed();
+ }
+}
+
+void SoundEngine::midiInit() {
+#ifdef WIN32
+ if (midiOutOpen((HMIDIOUT*)&_mo, MIDI_MAPPER, NULL, NULL, 0) != MMSYSERR_NOERROR)
+ error("midiOutOpen failed");
+#endif
+}
+
+#ifdef WIN32
+#define MIDI_OUT(a,b) midiOutShortMsg((HMIDIOUT)(a), (b))
+#else
+#define MIDI_OUT(a,b)
+#endif
+
+void SoundEngine::midiPitchBend(byte chan, int16 pitchbend) {
+ uint16 tmp;
+
+ if (_midi_pitchbend_last[chan] != pitchbend) {
+ _midi_pitchbend_last[chan] = pitchbend;
+ tmp = (pitchbend<<2) + 0x2000;
+ MIDI_OUT(_mo, ((tmp>>7)&0x7F)<<16 | (tmp&0x7F)<<8 | 0xE0 | chan);
+ }
+}
+
+void SoundEngine::midiVolume(byte chan, byte volume) {
+ if (_midi_volume_last[chan] != volume) {
+ _midi_volume_last[chan] = volume;
+ MIDI_OUT(_mo, volume<<16 | 7<<8 | 0xB0 | chan);
+ }
+}
+void SoundEngine::midiPedal(byte chan, bool pedal) {
+ if (_midi_pedal_last[chan] != pedal) {
+ _midi_pedal_last[chan] = pedal;
+ MIDI_OUT(_mo, pedal<<16 | 64<<8 | 0xB0 | chan);
+ }
+}
+
+void SoundEngine::midiModWheel(byte chan, byte modwheel) {
+ if (_midi_modwheel_last[chan] != modwheel) {
+ _midi_modwheel_last[chan] = modwheel;
+ MIDI_OUT(_mo, modwheel<<16 | 1<<8 | 0xB0 | chan);
+ }
+}
+
+void SoundEngine::midiEffectLevel(byte chan, byte level) {
+ if (_midi_effectlevel_last[chan] != level) {
+ _midi_effectlevel_last[chan] = level;
+ MIDI_OUT(_mo, level<<16 | 91<<8 | 0xB0 | chan);
+ }
+}
+
+void SoundEngine::midiChorus(byte chan, byte chorus) {
+ if (_midi_chorus_last[chan] != chorus) {
+ _midi_chorus_last[chan] = chorus;
+ MIDI_OUT(_mo, chorus<<16 | 93<<8 | 0xB0 | chan);
+ }
+}
+
+void SoundEngine::midiControl0(byte chan, byte value) {
+ MIDI_OUT(_mo, value<<16 | 0<<8 | 0xB0 | chan);
+}
+
+void SoundEngine::midiProgram(byte chan, byte program) {
+ MIDI_OUT(_mo, program<<8 | 0xC0 | chan);
+}
+
+void SoundEngine::midiPan(byte chan, int8 pan) {
+ if (_midi_pan_last[chan] != pan) {
+ _midi_pan_last[chan] = pan;
+ MIDI_OUT(_mo, ((pan-64)&0x7F)<<16 | 10<<8 | 0xB0 | chan);
+ }
+}
+
+void SoundEngine::midiNoteOn(byte chan, byte note, byte velocity) {
+ MIDI_OUT(_mo, velocity<<16 | note<<8 | 0x90 | chan);
+}
+
+void SoundEngine::midiNoteOff(byte chan, byte note) {
+ MIDI_OUT(_mo, note<<8 | 0x80 | chan);
+}
+
+void SoundEngine::midiSilence(byte chan) {
+ MIDI_OUT(_mo, (64<<8)|0xB0|chan);
+ MIDI_OUT(_mo, (123<<8)|0xB0|chan);
+} \ No newline at end of file
diff --git a/resource.cpp b/resource.cpp
index fd930af9b0..ff784e006e 100644
--- a/resource.cpp
+++ b/resource.cpp
@@ -551,12 +551,12 @@ byte *Scumm::getResourceAddress(int type, int index) {
ensureResourceLoaded(type, index);
}
- setResourceCounter(type, index, 1);
-
ptr=(byte*)res.address[type][index];
if (!ptr)
return NULL;
+ setResourceCounter(type, index, 1);
+
return ptr + sizeof(ResHeader);
}
diff --git a/saveload.cpp b/saveload.cpp
index 49c4cdd1e9..615d89ad78 100644
--- a/saveload.cpp
+++ b/saveload.cpp
@@ -21,6 +21,7 @@
#include "stdafx.h"
#include "scumm.h"
+#include "sound.h"
struct SaveGameHeader {
uint32 type;
@@ -29,7 +30,7 @@ struct SaveGameHeader {
char name[32];
};
-#define CURRENT_VER 4
+#define CURRENT_VER 5
bool Scumm::saveState(int slot, bool compat) {
char filename[256];
@@ -67,6 +68,7 @@ bool Scumm::loadState(int slot, bool compat) {
SaveGameHeader hdr;
Serializer ser;
int sb,sh;
+ SoundEngine *se;
makeSavegameName(filename, slot, compat);
out = fopen(filename,"rb");
@@ -88,7 +90,9 @@ bool Scumm::loadState(int slot, bool compat) {
}
memcpy(_saveLoadName, hdr.name, sizeof(hdr.name));
-
+
+ pauseSounds(true);
+
CHECK_HEAP
openRoom(-1);
@@ -134,6 +138,8 @@ bool Scumm::loadState(int slot, bool compat) {
debug(1,"State loaded from '%s'", filename);
+ pauseSounds(false);
+
return true;
}
@@ -413,20 +419,22 @@ void Scumm::saveOrLoad(Serializer *s) {
};
const SaveLoadEntry stringTabEntries[] = {
+ MKLINE(StringTab,xpos,sleInt16),
MKLINE(StringTab,t_xpos,sleInt16),
+ MKLINE(StringTab,ypos,sleInt16),
MKLINE(StringTab,t_ypos,sleInt16),
+ MKLINE(StringTab,right,sleInt16),
+ MKLINE(StringTab,t_right,sleInt16),
+ MKLINE(StringTab,color,sleInt8),
+ MKLINE(StringTab,t_color,sleInt8),
+ MKLINE(StringTab,charset,sleInt8),
+ MKLINE(StringTab,t_charset,sleInt8),
+ MKLINE(StringTab,center,sleByte),
MKLINE(StringTab,t_center,sleByte),
+ MKLINE(StringTab,overhead,sleByte),
MKLINE(StringTab,t_overhead,sleByte),
+ MKLINE(StringTab,no_talk_anim,sleByte),
MKLINE(StringTab,t_no_talk_anim,sleByte),
- MKLINE(StringTab,t_right,sleInt16),
- MKLINE(StringTab,t_color,sleInt16),
- MKLINE(StringTab,t_charset,sleInt16),
- MKLINE(StringTab,xpos,sleInt16),
- MKLINE(StringTab,ypos,sleInt16),
- MKLINE(StringTab,center,sleInt16),
- MKLINE(StringTab,overhead,sleInt16),
- MKLINE(StringTab,no_talk_anim,sleInt16),
- MKLINE(StringTab,right,sleInt16),
MKEND()
};
@@ -478,6 +486,9 @@ void Scumm::saveOrLoad(Serializer *s) {
res.flags[r][s->loadWord()] |= 0x80;
}
}
+
+ if (_soundDriver)
+ ((SoundEngine*)_soundDriver)->save_or_load(s);
}
void Scumm::saveLoadResource(Serializer *ser, int type, int index) {
@@ -630,9 +641,10 @@ void Serializer::saveLoadEntries(void *d, const SaveLoadEntry *sle) {
int replen;
byte type;
byte *at;
-
int size;
int value;
+ int num;
+ void *ptr;
while(sle->offs != 0xFFFF) {
at = (byte*)d + sle->offs;
@@ -642,10 +654,12 @@ void Serializer::saveLoadEntries(void *d, const SaveLoadEntry *sle) {
if (size==0xFF) {
if (_saveOrLoad) {
/* save reference */
- saveWord((*_save_ref)(_ref_me, type, *((void**)at)));
+ ptr = *((void**)at);
+ saveWord(ptr ? ((*_save_ref)(_ref_me, type, ptr ) + 1) : 0);
} else {
/* load reference */
- *((void**)at) = (*_load_ref)(_ref_me, type, loadWord());
+ num = loadWord();
+ *((void**)at) = num ? (*_load_ref)(_ref_me, type, num-1) : NULL;
}
} else {
replen = 1;
@@ -655,8 +669,8 @@ void Serializer::saveLoadEntries(void *d, const SaveLoadEntry *sle) {
type&=~128;
}
saveLoadArrayOf(at, replen, size, type);
- sle++;
}
+ sle++;
}
}
diff --git a/script_v1.cpp b/script_v1.cpp
index 910f10942a..11bcef6e0a 100644
--- a/script_v1.cpp
+++ b/script_v1.cpp
@@ -1227,7 +1227,7 @@ void Scumm::o5_putActorInRoom() {
void Scumm::o5_quitPauseRestart() {
switch(fetchScriptByte()) {
case 1:
- pauseGame(0);
+ pauseGame(false);
break;
case 3:
shutDown(0);
diff --git a/script_v2.cpp b/script_v2.cpp
index 0f7403a9c9..e390e5bf5a 100644
--- a/script_v2.cpp
+++ b/script_v2.cpp
@@ -1794,7 +1794,7 @@ void Scumm::o6_isAnyOf() {
void Scumm::o6_quitPauseRestart() {
switch(fetchScriptByte()) {
case 158:
- pauseGame(0);
+ pauseGame(false);
break;
case 160:
shutDown(0);
diff --git a/scumm.h b/scumm.h
index 04db276adb..3082253360 100644
--- a/scumm.h
+++ b/scumm.h
@@ -28,8 +28,14 @@ struct Actor;
typedef void (Scumm::*OpcodeProc)();
-#define NUM_SCRIPT_SLOT 25
-#define NUM_ACTORS 13
+/* System Wide Constants */
+enum {
+ SAMPLES_PER_SEC = 22050,
+ BITS_PER_SAMPLE = 16,
+ NUM_MIXER = 4,
+ NUM_SCRIPT_SLOT = 25,
+ NUM_ACTORS = 13
+};
#pragma START_PACK_STRUCTS
@@ -596,6 +602,16 @@ struct Gdi {
void updateDirtyScreen(VirtScreen *vs);
};
+struct MixerChannel {
+ void *_sfx_sound;
+ uint32 _sfx_pos;
+ uint32 _sfx_size;
+ uint32 _sfx_fp_speed;
+ uint32 _sfx_fp_pos;
+
+ void mix(int16 *data, uint32 len);
+ void clear();
+};
enum GameId {
GID_TENTACLE = 1,
@@ -640,6 +656,8 @@ struct Scumm {
bool _dynamicRoomOffsets;
byte _resFilePathId;
+ bool _soundsPaused;
+
bool _useTalkAnims;
char *_resFilePrefix;
@@ -918,6 +936,8 @@ struct Scumm {
char _saveLoadName[32];
+ MixerChannel _mixer_channel[NUM_MIXER];
+
OpcodeProc getOpcode(int i) { return _opcodes[i]; }
void openRoom(int room);
@@ -925,7 +945,6 @@ struct Scumm {
void readRoomsOffsets();
void askForDisk(const char *filename);
-
bool openResourceFile(const char *filename);
void fileClose(void *file);
@@ -1449,7 +1468,7 @@ struct Scumm {
void addObjectToInventory(uint obj, uint room);
void removeObjectFromRoom(int obj);
void decodeParseString();
- void pauseGame(int i);
+ void pauseGame(bool user);
void shutDown(int i);
void lock(int type, int i);
void unlock(int type, int i);
@@ -1590,6 +1609,7 @@ struct Scumm {
void talkSound(uint32 a, uint32 b, int mode);
void processSfxQueues();
void startTalkSound(uint32 a, uint32 b, int mode);
+ void stopTalkSound();
bool isMouthSyncOff(uint pos);
void startSfxSound(void *file);
void *openSfxFile();
@@ -1631,6 +1651,17 @@ struct Scumm {
void drawEnqueuedObject(EnqueuedObject *eo);
void removeEnqueuedObjects();
void removeEnqueuedObject(EnqueuedObject *eo);
+
+ void pauseSounds(bool pause);
+
+ MixerChannel *allocateMixer();
+ bool isSfxFinished();
+ void playSfxSound(void *sound, uint32 size, uint rate);
+ void stopSfxSound();
+
+ void mixWaves(int16 *sounds, int len);
+
+
};
struct ScummDebugger {
@@ -1671,6 +1702,7 @@ struct Serializer {
union {
SerializerSaveReference *_save_ref;
SerializerLoadReference *_load_ref;
+ void *_saveload_ref;
};
void *_ref_me;
@@ -1690,6 +1722,7 @@ struct Serializer {
uint32 loadUint32();
bool isSaving() { return _saveOrLoad; }
+
};
@@ -1714,4 +1747,4 @@ void blit(byte *dst, byte *src, int w, int h);
byte *findResource(uint32 id, byte *searchin, int index);
void playSfxSound(void *sound, uint32 size, uint rate);
bool isSfxFinished();
-void waitForTimer(Scumm *s, int delay); \ No newline at end of file
+void waitForTimer(Scumm *s, int msec_delay); \ No newline at end of file
diff --git a/scummvm.cpp b/scummvm.cpp
index cbccfcafc4..7c6af80dd7 100644
--- a/scummvm.cpp
+++ b/scummvm.cpp
@@ -196,8 +196,8 @@ void Scumm::scummMain(int argc, char **argv) {
_debugMode = 1;
- _maxHeapThreshold = 500000;
- _minHeapThreshold = 450000;
+ _maxHeapThreshold = 450000;
+ _minHeapThreshold = 400000;
parseCommandLine(argc, argv);
@@ -213,6 +213,11 @@ void Scumm::scummMain(int argc, char **argv) {
_bootParam = -7873;
}
+ if (_gameId==GID_MONKEY2 && _bootParam==0) {
+ _bootParam = 10001;
+ }
+
+
initGraphics(this, _fullScreen);
if (_majorScummVersion==6)
@@ -752,9 +757,8 @@ void Scumm::unkRoomFunc4(int a, int b, int c, int d, int e) {
warning("unkRoomFunc4: not implemented");
}
-void Scumm::pauseGame(int i) {
- /* TODO: implement this */
- warning("pauseGame: not implemented");
+void Scumm::pauseGame(bool user) {
+ ((Gui*)_gui)->pause();
}
void Scumm::shutDown(int i) {
@@ -777,12 +781,12 @@ void Scumm::processKbd() {
if (_lastKeyHit==_vars[VAR_RESTART_KEY]) {
warning("Restart not implemented");
- pauseGame(1);
+// pauseGame(true);
return;
}
if (_lastKeyHit==_vars[VAR_PAUSE_KEY]) {
- warning("Pause not implemented");
+ pauseGame(true);
/* pause */
return;
}
@@ -793,6 +797,8 @@ void Scumm::processKbd() {
((Gui*)_gui)->saveLoadDialog();
} else if (_lastKeyHit==_vars[VAR_TALKSTOP_KEY]) {
_talkDelay = 0;
+ if (_sfxMode==2)
+ stopTalk();
return;
}
diff --git a/scummvm.dsp b/scummvm.dsp
index 0ce6da4ec1..8b0963385e 100644
--- a/scummvm.dsp
+++ b/scummvm.dsp
@@ -42,7 +42,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /Zp4 /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "DUMP_SCRIPTS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /Zp4 /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD BASE RSC /l 0x41d /d "NDEBUG"
# ADD RSC /l 0x41d /d "NDEBUG"
BSC32=bscmake.exe
@@ -157,6 +157,10 @@ SOURCE=.\gui.cpp
# End Source File
# Begin Source File
+SOURCE=.\imuse.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\object.cpp
!IF "$(CFG)" == "scummvm - Win32 Release"
@@ -335,6 +339,10 @@ SOURCE=.\scummsys.h
# End Source File
# Begin Source File
+SOURCE=.\sound.h
+# End Source File
+# Begin Source File
+
SOURCE=.\StdAfx.h
# End Source File
# End Group
diff --git a/sdl.cpp b/sdl.cpp
index 0a769066d3..e62d577028 100644
--- a/sdl.cpp
+++ b/sdl.cpp
@@ -24,10 +24,9 @@
#include "stdafx.h"
#include "scumm.h"
#include "gui.h"
-
-#if defined(USE_IMUSE)
#include "sound.h"
-#endif
+
+#include "SDL_thread.h"
#define SCALEUP_2x2
@@ -35,9 +34,7 @@ Scumm scumm;
ScummDebugger debugger;
Gui gui;
-#if defined(USE_IMUSE)
SoundEngine sound;
-#endif
static SDL_Surface *screen;
@@ -74,78 +71,90 @@ int mapKey(int key, byte mod) {
return key;
}
-void waitForTimer(Scumm *s, int delay) {
+void waitForTimer(Scumm *s, int msec_delay) {
SDL_Event event;
-
- while (SDL_PollEvent(&event)) {
- switch(event.type) {
- case SDL_KEYDOWN:
- s->_keyPressed = mapKey(event.key.keysym.sym, event.key.keysym.mod);
- if (event.key.keysym.sym >= '0' && event.key.keysym.sym<='9') {
- s->_saveLoadSlot = event.key.keysym.sym - '0';
- if (event.key.keysym.mod&KMOD_SHIFT) {
- sprintf(s->_saveLoadName, "Quicksave %d", s->_saveLoadSlot);
- s->_saveLoadFlag = 1;
- } else if (event.key.keysym.mod&KMOD_CTRL)
- s->_saveLoadFlag = 2;
- s->_saveLoadCompatible = false;
- }
- if (event.key.keysym.sym=='z' && event.key.keysym.mod&KMOD_CTRL) {
- exit(1);
- }
- if (event.key.keysym.sym=='f' && event.key.keysym.mod&KMOD_CTRL) {
- s->_fastMode ^= 1;
- }
- if (event.key.keysym.sym=='g' && event.key.keysym.mod&KMOD_CTRL) {
- s->_fastMode ^= 2;
- }
+ uint32 start_time;
- if (event.key.keysym.sym=='d' && event.key.keysym.mod&KMOD_CTRL) {
- debugger.attach(s);
- }
- if (event.key.keysym.sym=='s' && event.key.keysym.mod&KMOD_CTRL) {
- s->resourceStats();
- }
+ if (msec_delay<0)
+ return;
+
+ if (s->_fastMode&2)
+ msec_delay = 0;
+ else if (s->_fastMode&1)
+ msec_delay = 10;
+
+ start_time = SDL_GetTicks();
+
+ do {
+ while (SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_KEYDOWN:
+ s->_keyPressed = mapKey(event.key.keysym.sym, event.key.keysym.mod);
+ if (event.key.keysym.sym >= '0' && event.key.keysym.sym<='9') {
+ s->_saveLoadSlot = event.key.keysym.sym - '0';
+ if (event.key.keysym.mod&KMOD_SHIFT) {
+ sprintf(s->_saveLoadName, "Quicksave %d", s->_saveLoadSlot);
+ s->_saveLoadFlag = 1;
+ } else if (event.key.keysym.mod&KMOD_CTRL)
+ s->_saveLoadFlag = 2;
+ s->_saveLoadCompatible = false;
+ }
+ if (event.key.keysym.sym=='z' && event.key.keysym.mod&KMOD_CTRL) {
+ exit(1);
+ }
+ if (event.key.keysym.sym=='f' && event.key.keysym.mod&KMOD_CTRL) {
+ s->_fastMode ^= 1;
+ }
+ if (event.key.keysym.sym=='g' && event.key.keysym.mod&KMOD_CTRL) {
+ s->_fastMode ^= 2;
+ }
-#if defined(__APPLE__)
- if (event.key.keysym.sym=='q' && event.key.keysym.mod&KMOD_LMETA) {
+ if (event.key.keysym.sym=='d' && event.key.keysym.mod&KMOD_CTRL) {
+ debugger.attach(s);
+ }
+ if (event.key.keysym.sym=='s' && event.key.keysym.mod&KMOD_CTRL) {
+ s->resourceStats();
+ }
+
+ #if defined(__APPLE__)
+ if (event.key.keysym.sym=='q' && event.key.keysym.mod&KMOD_LMETA) {
+ exit(1);
+ }
+ #endif
+ break;
+ case SDL_MOUSEMOTION: {
+ int newx,newy;
+ #if !defined(SCALEUP_2x2)
+ newx = event.motion.x;
+ newy = event.motion.y;
+ #else
+ newx = event.motion.x>>1;
+ newy = event.motion.y>>1;
+ #endif
+ if (newx != s->mouse.x || newy != s->mouse.y) {
+ s->mouse.x = newx;
+ s->mouse.y = newy;
+ s->drawMouse();
+ updateScreen(s);
+ }
+ break;
+ }
+ case SDL_MOUSEBUTTONDOWN:
+ if (event.button.button==SDL_BUTTON_LEFT)
+ s->_leftBtnPressed |= 1;
+ else if (event.button.button==SDL_BUTTON_RIGHT)
+ s->_rightBtnPressed |= 1;
+ break;
+ case SDL_QUIT:
exit(1);
- }
-#endif
- break;
- case SDL_MOUSEMOTION: {
- int newx,newy;
-#if !defined(SCALEUP_2x2)
- newx = event.motion.x;
- newy = event.motion.y;
-#else
- newx = event.motion.x>>1;
- newy = event.motion.y>>1;
-#endif
- if (newx != s->mouse.x || newy != s->mouse.y) {
- s->mouse.x = newx;
- s->mouse.y = newy;
- s->drawMouse();
- updateScreen(s);
+ break;
}
- break;
- }
- case SDL_MOUSEBUTTONDOWN:
- if (event.button.button==SDL_BUTTON_LEFT)
- s->_leftBtnPressed |= 1;
- else if (event.button.button==SDL_BUTTON_RIGHT)
- s->_rightBtnPressed |= 1;
- break;
- case SDL_QUIT:
- exit(1);
- break;
}
- }
-
- if (!(s->_fastMode&2)) {
- assert(delay<500);
- SDL_Delay(delay*10);
- }
+
+ if (SDL_GetTicks() >= start_time + msec_delay)
+ break;
+ SDL_Delay(10);
+ } while (1);
}
#define MAX_DIRTY_RECTS 40
@@ -468,111 +477,31 @@ void drawMouse(Scumm *s, int xdraw, int ydraw, int color, byte *mask, bool visib
old_mouse_x = xdraw;
old_mouse_y = ydraw;
}
-
-}
-
-#define SAMPLES_PER_SEC 22050
-#define BUFFER_SIZE (8192)
-#define BITS_PER_SAMPLE 16
-
-struct MixerChannel {
- void *_sfx_sound;
- uint32 _sfx_pos;
- uint32 _sfx_size;
- uint32 _sfx_fp_speed;
- uint32 _sfx_fp_pos;
-
- void mix(int16 *data, uint32 len);
- void clear();
-};
-
-#define NUM_MIXER 4
-
-static MixerChannel mixer_channel[NUM_MIXER];
-
-MixerChannel *find_channel() {
- int i;
- MixerChannel *mc = mixer_channel;
- for(i=0; i<NUM_MIXER; i++,mc++) {
- if (!mc->_sfx_sound)
- return mc;
- }
- return NULL;
-}
-
-
-bool isSfxFinished() {
- int i;
- for(i=0; i<NUM_MIXER; i++)
- if (mixer_channel[i]._sfx_sound)
- return false;
- return true;
}
-void playSfxSound(void *sound, uint32 size, uint rate) {
- MixerChannel *mc = find_channel();
-
- if (!mc) {
- warning("No mixer channel available");
- return;
- }
-
- mc->_sfx_sound = sound;
- mc->_sfx_pos = 0;
- mc->_sfx_fp_speed = (1<<16) * rate / 22050;
- mc->_sfx_fp_pos = 0;
+static uint32 midi_counter;
- while (size&0xFFFF0000) size>>=1, rate>>=1;
- mc->_sfx_size = size * 22050 / rate;
+void fill_sound(void *userdata, Uint8 *stream, int len) {
+ memset(stream, 0, len);
+ scumm.mixWaves((int16*)stream, len>>1);
}
-void MixerChannel::mix(int16 *data, uint32 len) {
- int8 *s;
- int i;
- uint32 fp_pos, fp_speed;
-
- if (!_sfx_sound)
- return;
- if (len > _sfx_size)
- len = _sfx_size;
- _sfx_size -= len;
+int music_thread(Scumm *s) {
+ int old_time, cur_time;
- s = (int8*)_sfx_sound + _sfx_pos;
- fp_pos = _sfx_fp_pos;
- fp_speed = _sfx_fp_speed;
+ old_time = SDL_GetTicks();
do {
- fp_pos += fp_speed;
- *data++ += (*s<<6);
- s += fp_pos >> 16;
- fp_pos &= 0x0000FFFF;
- } while (--len);
-
- _sfx_pos = s - (int8*)_sfx_sound;
- _sfx_fp_speed = fp_speed;
- _sfx_fp_pos = fp_pos;
-
- if (!_sfx_size)
- clear();
-}
-
-void MixerChannel::clear() {
- free(_sfx_sound);
- _sfx_sound = NULL;
-}
-
-void fill_sound(void *userdata, Uint8 *stream, int len) {
- int i;
-
-#if defined(USE_IMUSE)
- sound.generate_samples((int16*)stream, len>>1);
-#else
- memset(stream, 0, len);
-#endif
+ SDL_Delay(10);
+
+ cur_time = SDL_GetTicks();
+ while (old_time < cur_time) {
+ old_time += 10;
+ sound.on_timer();
+ }
+ } while (1);
- for(i=NUM_MIXER-1; i>=0;i--) {
- mixer_channel[i].mix((int16*)stream, len>>1);
- }
+ return 0;
}
void initGraphics(Scumm *s, bool fullScreen) {
@@ -599,10 +528,12 @@ void initGraphics(Scumm *s, bool fullScreen) {
SDL_OpenAudio(&desired, NULL);
SDL_PauseAudio(0);
-
SDL_WM_SetCaption(buf,buf);
SDL_ShowCursor(SDL_DISABLE);
+ /* Create Music Thread */
+ SDL_CreateThread((int (*)(void *))&music_thread, &scumm);
+
#if !defined(SCALEUP_2x2)
screen = SDL_SetVideoMode(320, 200, 8, fullScreen ? (SDL_SWSURFACE | SDL_FULLSCREEN) : SDL_SWSURFACE);
#else
@@ -627,33 +558,31 @@ void initGraphics(Scumm *s, bool fullScreen) {
int main(int argc, char* argv[]) {
int delta,tmp;
+ int last_time, new_time;
-#if defined(USE_IMUSE)
- sound.initialize(NULL);
+ sound.initialize(&scumm);
scumm._soundDriver = &sound;
-#endif
scumm._gui = &gui;
scumm.scummMain(argc, argv);
gui.init(&scumm);
+ last_time = SDL_GetTicks();
delta = 0;
do {
updateScreen(&scumm);
+ new_time = SDL_GetTicks();
+ waitForTimer(&scumm, delta * 15 + last_time - new_time);
+ last_time = SDL_GetTicks();
+
if (gui._active) {
gui.loop();
- tmp = 5;
+ delta = 5;
} else {
- tmp = delta = scumm.scummLoop(delta);
- tmp += tmp>>1;
-
- if (scumm._fastMode)
- tmp=1;
+ delta = scumm.scummLoop(delta);
}
-
- waitForTimer(&scumm, tmp);
} while(1);
return 0;
diff --git a/sound.cpp b/sound.cpp
index d4304d5f22..1590e1ff42 100644
--- a/sound.cpp
+++ b/sound.cpp
@@ -21,20 +21,7 @@
#include "stdafx.h"
#include "scumm.h"
-
-#if defined(USE_IMUSE)
#include "sound.h"
-#else
-struct SoundEngine {
- byte **_base_sounds;
- int start_sound(int sound) { return -1; }
- int stop_sound(int sound) { return -1; }
- int stop_all_sounds() { return -1; }
- int32 do_command(int a, int b, int c, int d, int e, int f, int g, int h) { return -1; }
- int get_sound_status(int sound) { return -1; }
- int clear_queue() { return -1; }
-};
-#endif
void Scumm::addSoundToQueue(int sound) {
_vars[VAR_LAST_SOUND] = sound;
@@ -170,6 +157,13 @@ void Scumm::startTalkSound(uint32 offset, uint32 b, int mode) {
startSfxSound(_sfxFile);
}
+void Scumm::stopTalkSound() {
+ if (_sfxMode==2) {
+ stopSfxSound();
+ _sfxMode = 0;
+ }
+}
+
bool Scumm::isMouthSyncOff(uint pos) {
uint j;
bool val = true;
@@ -203,7 +197,6 @@ int Scumm::isSoundRunning(int sound) {
if (!isResourceLoaded(rtSound, sound))
return 0;
-
se = (SoundEngine*)_soundDriver;
if (!se)
@@ -251,6 +244,7 @@ void Scumm::stopAllSounds() {
se->clear_queue();
}
clearSoundQue();
+ stopSfxSound();
}
void Scumm::clearSoundQue() {
@@ -283,27 +277,41 @@ void Scumm::talkSound(uint32 a, uint32 b, int mode) {
_talk_sound_mode = mode;
}
+/* The sound code currently only supports General Midi.
+ * General Midi is used in Day Of The Tentacle.
+ * Roland music is also playable, but doesn't sound well.
+ * A mapping between roland instruments and GM instruments
+ * is needed.
+ */
+
static const uint32 sound_tags[] = {
- MKID('ADL ')
+ MKID('GMD ')
};
void Scumm::setupSound() {
SoundEngine *se = (SoundEngine*)_soundDriver;
- if (se) {
+ if (se)
se->_base_sounds = res.address[rtSound];
- }
+
_soundTagTable = (byte*)sound_tags;
_numSoundTags = 1;
_sfxFile = openSfxFile();
}
+void Scumm::pauseSounds(bool pause) {
+ SoundEngine *se = (SoundEngine*)_soundDriver;
+ if (se)
+ se->pause(pause);
+ _soundsPaused = pause;
+}
+
struct VOCHeader {
byte id[19];
byte extra[7];
};
static const char VALID_VOC_ID[] = "Creative Voice File";
-static const char VALID_VOC_VERSION[] = "";
+
void Scumm::startSfxSound(void *file) {
VOCHeader hdr;
int block_type;
@@ -354,4 +362,98 @@ void Scumm::startSfxSound(void *file) {
void *Scumm::openSfxFile() {
return fopen("monster.sou", "rb");
-} \ No newline at end of file
+}
+
+#define NUM_MIXER 4
+
+MixerChannel *Scumm::allocateMixer() {
+ int i;
+ MixerChannel *mc = _mixer_channel;
+ for(i=0; i<NUM_MIXER; i++,mc++) {
+ if (!mc->_sfx_sound)
+ return mc;
+ }
+ return NULL;
+}
+
+void Scumm::stopSfxSound() {
+ MixerChannel *mc = _mixer_channel;
+ int i;
+ for(i=0; i<NUM_MIXER; i++,mc++) {
+ if (mc->_sfx_sound)
+ mc->clear();
+ }
+}
+
+
+bool Scumm::isSfxFinished() {
+ int i;
+ for(i=0; i<NUM_MIXER; i++)
+ if (_mixer_channel[i]._sfx_sound)
+ return false;
+ return true;
+}
+
+void Scumm::playSfxSound(void *sound, uint32 size, uint rate) {
+ MixerChannel *mc = allocateMixer();
+
+ if (!mc) {
+ warning("No mixer channel available");
+ return;
+ }
+
+ mc->_sfx_sound = sound;
+ mc->_sfx_pos = 0;
+ mc->_sfx_fp_speed = (1<<16) * rate / 22050;
+ mc->_sfx_fp_pos = 0;
+
+ while (size&0xFFFF0000) size>>=1, rate>>=1;
+ mc->_sfx_size = size * 22050 / rate;
+}
+
+void MixerChannel::mix(int16 *data, uint32 len) {
+ int8 *s;
+ int i;
+ uint32 fp_pos, fp_speed;
+
+ if (!_sfx_sound)
+ return;
+ if (len > _sfx_size)
+ len = _sfx_size;
+ _sfx_size -= len;
+
+ s = (int8*)_sfx_sound + _sfx_pos;
+ fp_pos = _sfx_fp_pos;
+ fp_speed = _sfx_fp_speed;
+
+ do {
+ fp_pos += fp_speed;
+ *data++ += (*s<<6);
+ s += fp_pos >> 16;
+ fp_pos &= 0x0000FFFF;
+ } while (--len);
+
+ _sfx_pos = s - (int8*)_sfx_sound;
+ _sfx_fp_speed = fp_speed;
+ _sfx_fp_pos = fp_pos;
+
+ if (!_sfx_size)
+ clear();
+}
+
+void MixerChannel::clear() {
+ free(_sfx_sound);
+ _sfx_sound = NULL;
+}
+
+void Scumm::mixWaves(int16 *sounds, int len) {
+ int i;
+
+ if (_soundsPaused)
+ return;
+
+ for(i=NUM_MIXER-1; i>=0;i--) {
+ _mixer_channel[i].mix(sounds, len);
+ }
+}
+
diff --git a/sound.h b/sound.h
new file mode 100644
index 0000000000..26ac251ee9
--- /dev/null
+++ b/sound.h
@@ -0,0 +1,358 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/11/14 18:37:38 strigeus
+ * music support,
+ * fixed timing bugs
+ *
+ */
+
+struct Part;
+struct MidiChannel;
+struct VolumeFader;
+struct Player;
+struct HookDatas;
+struct SoundEngine;
+
+struct Part {
+ SoundEngine *_se;
+ Part *_next, *_prev;
+ MidiChannel *_mc;
+ Player *_player;
+ int16 _pitchbend;
+ byte _pitchbend_factor;
+ int8 _transpose,_transpose_eff;
+ byte _vol,_vol_eff;
+ int8 _detune,_detune_eff;
+ int8 _pan,_pan_eff;
+ bool _on;
+ byte _modwheel;
+ bool _pedal;
+ byte _program;
+ int8 _pri;
+ byte _pri_eff;
+ byte _chan;
+ byte _effect_level;
+ byte _chorus;
+ byte _gmidi_5;
+ byte _gmidi_1;
+
+ void key_on(byte note, byte velocity);
+ void key_off(byte note);
+ void set_param(int b, byte c) {}
+ void init(SoundEngine *se);
+ void setup(Player *player);
+ void uninit();
+ void off();
+ void silence();
+ void set_instrument(uint b);
+ void set_instrument(byte *data) {}
+
+ void set_transpose(int8 transpose);
+ void set_vol(uint8 volume);
+ void set_detune(int8 detune);
+ void set_pri(int8 pri, bool recalc);
+ void set_pan(int8 pan);
+ void set_modwheel(uint value);
+ void set_pedal(bool value);
+ void set_pitchbend(int value);
+ void release_pedal();
+ void set_program(byte program);
+ void set_chorus(uint chorus);
+ void set_effect_level(uint level);
+ void set_chan_param(int b, int c) {}
+ void mod_changed();
+ void vol_changed();
+ void pedal_changed();
+ void modwheel_changed();
+ void pan_changed();
+ void effect_level_changed();
+ void program_changed();
+ void chorus_changed();
+ int update_actives(uint16 *active);
+ void set_pitchbend_factor(uint8 value);
+ void set_onoff(bool on);
+
+ void fix_after_load();
+};
+
+struct MidiChannel {
+ Part *_part;
+ byte _chan;
+ uint16 _actives[8];
+
+ void init(byte chan);
+};
+
+struct VolumeFader {
+ Player *player;
+ bool active;
+ byte curvol;
+ uint16 speed_lo_max,num_steps;
+ int8 speed_hi;
+ int8 direction;
+ int8 speed_lo;
+ uint16 speed_lo_counter;
+
+ void initialize() { active = false; }
+ void on_timer();
+};
+
+struct HookDatas {
+ byte _jump,_transpose;
+ byte _part_onoff[16];
+ byte _part_volume[16];
+ byte _part_program[16];
+ byte _part_transpose[16];
+
+ int query_param(int param, byte chan);
+ int set(byte cls, byte value, byte chan);
+};
+
+struct Player {
+ SoundEngine *_se;
+
+ Part *_parts;
+ bool _active;
+ bool _scanning;
+ int _id;
+ byte _priority;
+ byte _volume;
+ int8 _pan;
+ int8 _transpose;
+ int8 _detune;
+ uint _vol_chan;
+ byte _vol_eff;
+
+ uint _song_index;
+ uint _track_index;
+ uint _timer_counter;
+ uint _loop_to_beat;
+ uint _loop_from_beat;
+ uint _loop_counter;
+ uint _loop_to_tick;
+ uint _loop_from_tick;
+ uint32 _tempo;
+ uint32 _tempo_eff; /* NoSave */
+ uint32 _cur_pos;
+ uint32 _next_pos;
+ uint32 _song_offset;
+ uint32 _timer_speed; /* NoSave */
+ uint _tick_index;
+ uint _beat_index;
+ uint _ticks_per_beat;
+ byte _speed; /* NoSave */
+ bool _abort;
+
+ HookDatas _hook;
+
+ /* Player part */
+ void hook_clear();
+ void clear();
+ bool start_sound(int sound);
+ void uninit_parts();
+ byte *parse_midi(byte *s);
+ void key_off(uint8 chan, byte data);
+ void key_on(uint8 chan, byte data, byte velocity);
+ void part_set_transpose(uint8 chan, byte relative, int8 b);
+ void parse_sysex(byte *p, uint len);
+ void maybe_jump(byte *data);
+ void maybe_set_transpose(byte *data);
+ void maybe_part_onoff(byte *data);
+ void maybe_set_volume(byte *data);
+ void maybe_set_program(byte *data);
+ void maybe_set_transpose_part(byte *data);
+ uint update_actives();
+ Part *get_part(uint8 part);
+ void turn_off_pedals();
+ int set_vol(byte vol);
+ int get_param(int param, byte chan);
+ int query_part_param(int param, byte chan);
+ int set_transpose(byte relative, int b);
+ void set_priority(int pri);
+ void set_pan(int pan);
+ void set_detune(int detune);
+ void silence_parts();
+ void play_active_notes();
+ void cancel_volume_fade();
+
+ static void decode_sysex_bytes(byte *src, byte *dst, int len);
+
+ void clear_active_note(int chan, byte note);
+ void set_active_note(int chan, byte note);
+ void clear_active_notes();
+
+ /* Sequencer part */
+ bool set_loop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick);
+ void clear_loop();
+ void set_speed(byte speed);
+ bool jump(uint track, uint beat, uint tick);
+ void uninit_seq();
+ void set_tempo(uint32 data);
+ int start_seq_sound(int sound);
+ void find_sustaining_notes(byte *a, byte *b, uint32 l);
+ int scan(uint totrack, uint tobeat, uint totick);
+ int query_param(int param);
+
+ int fade_vol(byte vol, int time);
+ void sequencer_timer();
+};
+
+
+struct SustainingNotes {
+ SustainingNotes *next;
+ SustainingNotes *prev;
+ Player *player;
+ byte note,chan;
+ uint32 off_pos;
+ uint32 pos;
+ uint16 counter;
+};
+
+struct CommandQueue {
+ uint16 array[8];
+};
+
+struct IsNoteCmdData {
+ byte chan;
+ byte note;
+ byte vel;
+};
+
+struct SoundEngine {
+ void *_mo; /* midi out */
+
+ byte **_base_sounds;
+
+ Scumm *_s;
+
+ byte _locked;
+
+ bool _paused;
+ bool _active_volume_faders;
+ bool _initialized;
+ byte _volume_fader_counter;
+
+ uint _queue_end, _queue_pos, _queue_sound;
+ byte _queue_adding;
+
+ SustainingNotes *_sustain_notes_used;
+ SustainingNotes *_sustain_notes_free;
+ SustainingNotes *_sustain_notes_head;
+
+ uint16 _timer_counter_1;
+
+ byte _queue_marker;
+ byte _queue_cleared;
+ byte _master_volume;
+
+ uint16 _trigger_count;
+
+ uint16 _channel_volume[8];
+ uint16 _channel_volume_eff[8]; /* NoSave */
+ uint16 _volchan_table[8];
+
+ Player _players[8];
+ SustainingNotes _sustaining_notes[24];
+ VolumeFader _volume_fader[8];
+ Part _parts[32];
+ MidiChannel _midi_channels[9];
+ uint16 _active_notes[128];
+ CommandQueue _cmd_queue[64];
+
+ int16 _midi_pitchbend_last[16];
+ uint8 _midi_volume_last[16];
+ bool _midi_pedal_last[16];
+ byte _midi_modwheel_last[16];
+ byte _midi_effectlevel_last[16];
+ byte _midi_chorus_last[16];
+ int8 _midi_pan_last[16];
+
+ byte *findTag(int sound, char *tag, int index);
+ int initialize(Scumm *scumm);
+ int terminate();
+ int save_or_load(Serializer *ser);
+ int set_master_volume(uint vol);
+ int get_master_volume();
+ bool start_sound(int sound);
+ int stop_sound(int sound);
+ int stop_all_sounds();
+ int get_sound_status(int sound);
+ int get_queue_sound_status(int sound);
+ Player *allocate_player(byte priority);
+ void handle_marker(uint id, byte data);
+ int get_channel_volume(uint a);
+ void init_players();
+ void init_parts();
+ void init_volume_fader();
+ void init_sustaining_notes();
+ void init_queue();
+
+ void on_timer();
+ void sequencer_timers();
+ void expire_sustain_notes();
+ void expire_volume_faders();
+
+ void set_instrument(uint slot, byte *data) {}
+
+ int32 do_command(int a, int b, int c, int d, int e, int f, int g, int h);
+ Part *allocate_part(byte pri);
+
+ int clear_queue();
+ int enqueue_command(int a, int b, int c, int d, int e, int f, int g);
+ int enqueue_trigger(int sound, int marker);
+ int query_queue(int param);
+ Player *get_player_byid(int id);
+
+ int get_volchan_entry(uint a);
+ int set_volchan_entry(uint a, uint b);
+ int set_channel_volume(uint chan, uint vol);
+ void update_volumes();
+ void reset_tick();
+ VolumeFader *allocate_volume_fader();
+
+ int set_volchan(int sound, int volchan);
+
+ void midiPitchBend(byte chan, int16 pitchbend);
+ void midiVolume(byte chan, byte volume);
+ void midiPedal(byte chan, bool pedal);
+ void midiModWheel(byte chan, byte modwheel);
+ void midiEffectLevel(byte chan, byte level);
+ void midiChorus(byte chan, byte chorus);
+ void midiControl0(byte chan, byte value);
+ void midiProgram(byte chan, byte program);
+ void midiPan(byte chan, int8 pan);
+ void midiNoteOn(byte chan, byte note, byte velocity);
+ void midiNoteOff(byte chan, byte note);
+ void midiSilence(byte chan);
+ void midiInit();
+
+ void adjust_priorities();
+
+ void fix_parts_after_load();
+ void fix_players_after_load();
+
+ static int saveReference(SoundEngine *me, byte type, void *ref);
+ static void *loadReference(SoundEngine *me, byte type, int ref);
+
+ void lock();
+ void unlock();
+
+ void pause(bool paused);
+};
diff --git a/string.cpp b/string.cpp
index 8b472b777d..b93cba2d8d 100644
--- a/string.cpp
+++ b/string.cpp
@@ -276,6 +276,8 @@ void Scumm::CHARSET_1() {
_lastXstart = virtscr[0].xstart;
if (charset._center) {
charset._xpos2 -= charset.getStringWidth(0, buffer,0) >> 1;
+ if (charset._xpos2<0)
+ charset._xpos2 = 0;
}
charset._disableOffsX = charset._unk12 = !_keepText;
diff --git a/windows.cpp b/windows.cpp
index 81290c0da6..07330d8916 100644
--- a/windows.cpp
+++ b/windows.cpp
@@ -31,11 +31,7 @@
#endif
#include "scumm.h"
-
-#if defined(USE_IMUSE)
#include "sound.h"
-#endif
-
#include "gui.h"
#if !defined(ALLOW_GDI)
@@ -135,10 +131,7 @@ int sel;
Scumm scumm;
ScummDebugger debugger;
Gui gui;
-
-#if defined(USE_IMUSE)
SoundEngine sound;
-#endif
WndMan wm[1];
byte veryFastMode;
@@ -819,95 +812,6 @@ void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
}
-#define SAMPLES_PER_SEC 22050
-#define BUFFER_SIZE (8192)
-#define BITS_PER_SAMPLE 16
-
-struct MixerChannel {
- void *_sfx_sound;
- uint32 _sfx_pos;
- uint32 _sfx_size;
- uint32 _sfx_fp_speed;
- uint32 _sfx_fp_pos;
-
- void mix(int16 *data, uint32 len);
- void clear();
-};
-
-#define NUM_MIXER 4
-
-static MixerChannel mixer_channel[NUM_MIXER];
-
-MixerChannel *find_channel() {
- int i;
- MixerChannel *mc = mixer_channel;
- for(i=0; i<NUM_MIXER; i++,mc++) {
- if (!mc->_sfx_sound)
- return mc;
- }
- return NULL;
-}
-
-
-bool isSfxFinished() {
- int i;
- for(i=0; i<NUM_MIXER; i++)
- if (mixer_channel[i]._sfx_sound)
- return false;
- return true;
-}
-
-void playSfxSound(void *sound, uint32 size, uint rate) {
- MixerChannel *mc = find_channel();
-
- if (!mc) {
- warning("No mixer channel available");
- return;
- }
-
- mc->_sfx_sound = sound;
- mc->_sfx_pos = 0;
- mc->_sfx_fp_speed = (1<<16) * rate / 22050;
- mc->_sfx_fp_pos = 0;
-
- while (size&0xFFFF0000) size>>=1, rate>>=1;
- mc->_sfx_size = size * 22050 / rate;
-}
-
-void MixerChannel::mix(int16 *data, uint32 len) {
- int8 *s;
- int i;
- uint32 fp_pos, fp_speed;
-
- if (!_sfx_sound)
- return;
- if (len > _sfx_size)
- len = _sfx_size;
- _sfx_size -= len;
-
- s = (int8*)_sfx_sound + _sfx_pos;
- fp_pos = _sfx_fp_pos;
- fp_speed = _sfx_fp_speed;
-
- do {
- fp_pos += fp_speed;
- *data++ += (*s<<6);
- s += fp_pos >> 16;
- fp_pos &= 0x0000FFFF;
- } while (--len);
-
- _sfx_pos = s - (int8*)_sfx_sound;
- _sfx_fp_speed = fp_speed;
- _sfx_fp_pos = fp_pos;
-
- if (!_sfx_size)
- clear();
-}
-
-void MixerChannel::clear() {
- free(_sfx_sound);
- _sfx_sound = NULL;
-}
int clock;
@@ -923,8 +827,8 @@ void updateScreen(Scumm *s) {
void waitForTimer(Scumm *s, int delay) {
wm->handleMessage();
if (!veryFastMode) {
- assert(delay<500);
- Sleep(delay*10);
+ assert(delay<5000);
+ Sleep(delay);
}
}
@@ -940,16 +844,8 @@ void drawMouse(Scumm *s, int x, int y, int w, int h, byte *buf, bool visible) {
}
void fill_buffer(int16 *buf, int len) {
- int i;
-#if defined(USE_IMUSE)
- sound.generate_samples(buf,len);
-#else
memset(buf, 0, len*2);
-#endif
- for(i=NUM_MIXER-1; i>=0;i--) {
- mixer_channel[i].mix((int16*)buf, len);
- }
-
+ scumm.mixWaves(buf, len);
}
void WndMan::prepare_header(WAVEHDR *wh, int i) {
@@ -975,6 +871,7 @@ void WndMan::sound_init() {
wfx.nBlockAlign = BITS_PER_SAMPLE * 1 / 8;
CreateThread(NULL, 0, (unsigned long (__stdcall *)(void *))&sound_thread, this, 0, &_threadId);
+ SetThreadPriority((void*)_threadId, THREAD_PRIORITY_HIGHEST);
_event = CreateEvent(NULL, false, false, NULL);
@@ -988,13 +885,25 @@ void WndMan::sound_init() {
DWORD _stdcall WndMan::sound_thread(WndMan *wm) {
int i;
+ bool signaled;
+ int time = GetTickCount(), cur;
+
while (1) {
- WaitForSingleObject(wm->_event, INFINITE);
- for(i=0; i<2; i++) {
- WAVEHDR *hdr = &wm->_hdr[i];
- if (hdr->dwFlags & WHDR_DONE) {
- fill_buffer((int16*)hdr->lpData, hdr->dwBufferLength>>1);
- waveOutWrite(wm->_handle, hdr, sizeof(WAVEHDR));
+ cur = GetTickCount();
+ while (time < cur) {
+ sound.on_timer();
+ time += 10;
+ }
+
+ signaled = WaitForSingleObject(wm->_event, time - cur) == WAIT_OBJECT_0;
+
+ if (signaled) {
+ for(i=0; i<2; i++) {
+ WAVEHDR *hdr = &wm->_hdr[i];
+ if (hdr->dwFlags & WHDR_DONE) {
+ fill_buffer((int16*)hdr->lpData, hdr->dwBufferLength>>1);
+ waveOutWrite(wm->_handle, hdr, sizeof(WAVEHDR));
+ }
}
}
}
@@ -1011,10 +920,8 @@ int main(int argc, char* argv[]) {
wm->_vgabuf = (byte*)calloc(320,200);
wm->_scumm = &scumm;
-#if defined(USE_IMUSE)
- sound.initialize(NULL);
+ sound.initialize(&scumm);
scumm._soundDriver = &sound;
-#endif
scumm._gui = &gui;
scumm.scummMain(argc, argv);
@@ -1024,6 +931,8 @@ int main(int argc, char* argv[]) {
do {
updateScreen(&scumm);
+ waitForTimer(&scumm, tmp*10);
+
if (gui._active) {
gui.loop();
tmp = 5;
@@ -1035,8 +944,6 @@ int main(int argc, char* argv[]) {
if (scumm._fastMode)
tmp=1;
}
-
- waitForTimer(&scumm, tmp);
} while(1);
return 0;