music support,

fixed timing bugs

svn-id: r3491
This commit is contained in:
Ludvig Strigeus 2001-11-14 18:40:39 +00:00
parent 279d5b2fd7
commit b8d259d60e
18 changed files with 3298 additions and 376 deletions

View file

@ -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 \

View file

@ -585,6 +585,8 @@ void Scumm::showActors() {
void Scumm::stopTalk() {
int act;
stopTalkSound();
_haveMsg = 0;
_talkDelay = 0;

View file

@ -1396,7 +1396,7 @@ void Scumm::unkScreenEffect7(int a) {
tab_2[i] += tab_1[i];
updateScreen(this);
waitForTimer(this,3);
waitForTimer(this,30);
}
}

47
gui.cpp
View file

@ -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,6 +412,8 @@ void Gui::editString(int i) {
}
void Gui::addLetter(byte letter) {
switch(_dialog) {
case SAVELOAD_DIALOG:
if (_editString==-1)
return;
@ -413,13 +428,12 @@ void Gui::addLetter(byte letter) {
_editLen--;
}
showCaret(true);
}
void Gui::saveLoadDialog() {
_widgets[0] = save_load_dialog;
_editString = -1;
_cur_page = 0;
_active = 1;
break;
case PAUSE_DIALOG:
if (letter==32)
close();
break;
}
}
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;
}

2
gui.h
View file

@ -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

2529
imuse.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -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);
}

View file

@ -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");
@ -89,6 +91,8 @@ 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,t_xpos,sleInt16),
MKLINE(StringTab,t_ypos,sleInt16),
MKLINE(StringTab,t_center,sleByte),
MKLINE(StringTab,t_overhead,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,t_xpos,sleInt16),
MKLINE(StringTab,ypos,sleInt16),
MKLINE(StringTab,center,sleInt16),
MKLINE(StringTab,overhead,sleInt16),
MKLINE(StringTab,no_talk_anim,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),
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++;
}
}

View file

@ -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);

View file

@ -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);

43
scumm.h
View file

@ -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);
void waitForTimer(Scumm *s, int msec_delay);

View file

@ -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;
}

View file

@ -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

179
sdl.cpp
View file

@ -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,9 +71,21 @@ int mapKey(int key, byte mod) {
return key;
}
void waitForTimer(Scumm *s, int delay) {
void waitForTimer(Scumm *s, int msec_delay) {
SDL_Event event;
uint32 start_time;
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:
@ -107,21 +116,21 @@ void waitForTimer(Scumm *s, int delay) {
s->resourceStats();
}
#if defined(__APPLE__)
#if defined(__APPLE__)
if (event.key.keysym.sym=='q' && event.key.keysym.mod&KMOD_LMETA) {
exit(1);
}
#endif
#endif
break;
case SDL_MOUSEMOTION: {
int newx,newy;
#if !defined(SCALEUP_2x2)
#if !defined(SCALEUP_2x2)
newx = event.motion.x;
newy = event.motion.y;
#else
#else
newx = event.motion.x>>1;
newy = event.motion.y>>1;
#endif
#endif
if (newx != s->mouse.x || newy != s->mouse.y) {
s->mouse.x = newx;
s->mouse.y = newy;
@ -142,10 +151,10 @@ void waitForTimer(Scumm *s, int delay) {
}
}
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;
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;
}
static uint32 midi_counter;
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
scumm.mixWaves((int16*)stream, len>>1);
}
for(i=NUM_MIXER-1; i>=0;i--) {
mixer_channel[i].mix((int16*)stream, len>>1);
int music_thread(Scumm *s) {
int old_time, cur_time;
old_time = SDL_GetTicks();
do {
SDL_Delay(10);
cur_time = SDL_GetTicks();
while (old_time < cur_time) {
old_time += 10;
sound.on_timer();
}
} while (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;

138
sound.cpp
View file

@ -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;
@ -204,7 +198,6 @@ int Scumm::isSoundRunning(int sound) {
if (!isResourceLoaded(rtSound, sound))
return 0;
se = (SoundEngine*)_soundDriver;
if (!se)
return 0;
@ -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;
@ -355,3 +363,97 @@ void Scumm::startSfxSound(void *file) {
void *Scumm::openSfxFile() {
return fopen("monster.sou", "rb");
}
#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);
}
}

358
sound.h Normal file
View file

@ -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);
};

View file

@ -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;

View file

@ -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,8 +885,19 @@ 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);
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) {
@ -998,6 +906,7 @@ DWORD _stdcall WndMan::sound_thread(WndMan *wm) {
}
}
}
}
}
@ -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;