diff --git a/gui/dialog.cpp b/gui/dialog.cpp index 59355cc0314..13651a1a800 100644 --- a/gui/dialog.cpp +++ b/gui/dialog.cpp @@ -489,8 +489,8 @@ void SoundDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) scumm->_imuse->set_music_volume(_soundVolumeMusic); scumm->_imuse->set_master_volume(_soundVolumeMaster); - scumm->_mixer->set_volume(_soundVolumeSfx); - scumm->_mixer->set_music_volume(_soundVolumeMusic); + scumm->_mixer->setVolume(_soundVolumeSfx); + scumm->_mixer->setMusicVolume(_soundVolumeMusic); scummcfg->set("master_volume", _soundVolumeMaster); scummcfg->set("music_volume", _soundVolumeMusic); diff --git a/gui/gui.cpp b/gui/gui.cpp index 270641ae17a..8b2515e4b5d 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -621,8 +621,8 @@ void Gui::handleSoundDialogCommand(int cmd) _s->_imuse->set_music_volume(_s->_sound->_sound_volume_music); _s->_imuse->set_master_volume(_s->_sound->_sound_volume_master); - _s->_mixer->set_volume(_s->_sound->_sound_volume_sfx); - _s->_mixer->set_music_volume(_s->_sound->_sound_volume_music); + _s->_mixer->setVolume(_s->_sound->_sound_volume_sfx); + _s->_mixer->setMusicVolume(_s->_sound->_sound_volume_music); scummcfg->set("master_volume", _s->_sound->_sound_volume_master); scummcfg->set("music_volume", _s->_sound->_sound_volume_music); diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp index 7a6742fbd46..2fe13515943 100644 --- a/scumm/imuse.cpp +++ b/scumm/imuse.cpp @@ -3302,7 +3302,7 @@ void IMuseAdlib::init(IMuseInternal *eng, OSystem *syst) adlib_write(0xBD, 0x00); create_lookup_table(); - _mixer->setup_premix(this, premix_proc); + _mixer->setupPremix(this, premix_proc); } void IMuseAdlib::adlib_write(byte port, byte value) diff --git a/scumm/insane.cpp b/scumm/insane.cpp index ef9dd779eb0..a4ad1f59d85 100644 --- a/scumm/insane.cpp +++ b/scumm/insane.cpp @@ -1467,7 +1467,7 @@ void SmushPlayer::startVideo(short int arg, byte *videoFile) { for (idx = 0; idx < MAX_STREAMER; idx++) { if (_imusTrk[idx] != 0) { if (_imusNewMixer[idx]) { - _scumm->_mixer->play_stream(NULL, idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]); + _scumm->_mixer->playStream(NULL, idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]); } else { _scumm->_mixer->append(idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]); } @@ -1479,7 +1479,7 @@ void SmushPlayer::startVideo(short int arg, byte *videoFile) { for (idx = 0; idx < MAX_STREAMER; idx++) { if (_psadTrk[idx] != 0) { if (_strkNewMixer[idx]) { - _scumm->_mixer->play_stream(NULL, idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + _scumm->_mixer->playStream(NULL, idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); } else { _scumm->_mixer->append(idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); } diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp index 0f3011721b0..e2e11d555b5 100644 --- a/scumm/saveload.cpp +++ b/scumm/saveload.cpp @@ -597,7 +597,7 @@ void Scumm::saveOrLoad(Serializer *s) int var98Backup; if (_mixer && !s->isSaving()) - _mixer->stop_all(); + _mixer->stopAll(); if (_current_version == VER_V9) s->saveLoadEntries(this, mainEntriesV9); diff --git a/scumm/script_v2.cpp b/scumm/script_v2.cpp index 5f85f746c20..5487e9dc1e6 100644 --- a/scumm/script_v2.cpp +++ b/scumm/script_v2.cpp @@ -24,7 +24,8 @@ #include "stdafx.h" #include "scumm.h" #include "actor.h" -#include "smush.h" +#include "smush/player.h" +#include "smush/scumm_renderer.h" #include "sound/mididrv.h" #include "scumm/imuse.h" @@ -2699,7 +2700,6 @@ void Scumm::o6_miscOps() Actor *a; IMuse *se = _imuse; //yazoo: not very nice - SmushPlayer * sp; getStackList(args, sizeof(args) / sizeof(args[0])); @@ -2708,11 +2708,15 @@ void Scumm::o6_miscOps() case 4: grabCursor(args[1], args[2], args[3], args[4]); break; - case 6: - sp = new SmushPlayer(this); - sp->startVideo(args[1], getStringAddressVar(VAR_VIDEONAME)); - delete sp; - break; + case 6: { + ScummRenderer sr(this); + SmushPlayer sp(&sr); + char filename[512]; + strcpy(filename, _gameDataPath); + strcat(filename, "video/"); + strcat(filename, (char*)getStringAddressVar(VAR_VIDEONAME)); + sp.play(filename); + } case 7: warning("o6_miscOps: stub7()"); break; diff --git a/scumm/smush/blitter.cpp b/scumm/smush/blitter.cpp new file mode 100644 index 00000000000..bbeb7a18647 --- /dev/null +++ b/scumm/smush/blitter.cpp @@ -0,0 +1,221 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "blitter.h" +#include "chunck.h" + +#include +#include // for memcpy + +#ifndef min +#define min(x, y) ((x) > (y) ? (y) : (x)) +#endif + +Blitter::Blitter(char * ptr, const Point & dstsize, const Rect & src) : + _ptr(ptr), + _clip(dstsize), + _src(src), + _cur(src.left(), src.top()), + _outside(false) { +#ifdef DEBUG_CLIPPER + _clipped = 0; + _clippedBlock = 0; +#endif + assert(_ptr); + assert(_clip.getX() > 0 && _clip.getY() > 0); + assert(_src.width() > 0 && _src.height() > 0); + assert(_src.left() < _clip.getX() && _src.right() <= _clip.getX()); + assert(_src.top() < _clip.getY() && _src.bottom() <= _clip.getY()); + _offset = _ptr + _clip.getX() * _cur.getY() + _cur.getX(); +} + +Blitter::~Blitter() { +#ifdef DEBUG_CLIPPER + if(_clipped || _clippedBlock) { + debug(3, "blitter clipped %d pixels and %d blocks", _clipped, _clippedBlock); + } +#endif +} + +void Blitter::advance(int x, int y) { + if(y != 0) { + _cur.set(_src.left() + x, _cur.getY() + y); + } else { + _cur.getX() += x; + if(_cur.getX() >= _src.right()) { + _cur.set(_src.left(), _cur.getY()+1); + } + } + _offset = _ptr + _clip.getX() * _cur.getY() + _cur.getX(); + _outside = ! _src.isInside(_cur); +} + +void Blitter::advanceBlock(int x, int y) { + advance(x*4, y*4); +} + +void Blitter::put(char data) { + if(!_outside) { + *_offset = data; + advance(); + } +#ifdef DEBUG_CLIPPER + else _clipped ++; +#endif +} + +void Blitter::put(char data, unsigned int len) { + while(len) { + if(_outside) { +#ifdef DEBUG_CLIPPER + _clipped += len; +#endif + break; + } + int l = min((int)len, min(_clip.getX() - _cur.getX(), _src.right() - _cur.getX())); + len -= l; + memset(_offset, data, l); + advance(l); + } +} + +void Blitter::blit(char * ptr, unsigned int len) { + while(len) { + if(_outside) { +#ifdef DEBUG_CLIPPER + _clipped += len; +#endif + break; + } + int l = min((int)len, min(_clip.getX() - _cur.getX(), _src.right() - _cur.getX())); + len -= l; + memcpy(_offset, ptr, l); + ptr += l; + advance(l); + } +} + +void Blitter::blit(Chunck & src, unsigned int len) { + while(len) { + if(_outside) { +#ifdef DEBUG_CLIPPER + _clipped += len; +#endif + break; + } + int l = min((int)len, min(_clip.getX() -_cur.getX(), _src.right() - _cur.getX())); + len -= l; + src.read(_offset, l); + advance(l); + } +} + +void Blitter::putBlock(unsigned int data) { + if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping + assert((_clip.getX() & 3) == 0); + unsigned int * dst = (unsigned int *)_offset; + int line_size = _clip.getX() >> 2; + + *dst = data; dst += line_size; + *dst = data; dst += line_size; + *dst = data; dst += line_size; + *dst = data; + +#ifdef DEBUG_CLIPPER + } else { + _clippedBlock ++; +#endif + } + advanceBlock(); +} + +void Blitter::putBlock(unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4) { + if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping + assert((_clip.getX() & 3) == 0); + unsigned int * dst = (unsigned int *)_offset; + int line_size = _clip.getX() >> 2; + + *dst = d4; dst += line_size; + *dst = d3; dst += line_size; + *dst = d2; dst += line_size; + *dst = d1; + +#ifdef DEBUG_CLIPPER + } else { + _clippedBlock ++; +#endif + } + advanceBlock(); +} + +void Blitter::putBlock(unsigned char * data) { + if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping + assert((_clip.getX() & 3) == 0); + unsigned int * dst = (unsigned int *)_offset; + int line_size = _clip.getX() >> 2; + unsigned int * src = (unsigned int *)data; + *dst = *src++; dst += line_size; + *dst = *src++; dst += line_size; + *dst = *src++; dst += line_size; + *dst = *src++; +#ifdef DEBUG_CLIPPER + } else { + _clippedBlock ++; +#endif + } + advanceBlock(); +} + +void Blitter::putBlock(Chunck & src) { + if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping + assert((_clip.getX() & 3) == 0); + unsigned int * dst = (unsigned int *)_offset; + int line_size = _clip.getX() >> 2; + *dst = src.getDword(); dst += line_size; + *dst = src.getDword(); dst += line_size; + *dst = src.getDword(); dst += line_size; + *dst = src.getDword(); +#ifdef DEBUG_CLIPPER + } else { + _clippedBlock ++; +#endif + } + advanceBlock(); +} + +void Blitter::blockCopy(int offset) { + if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) {// This is clipping + char * dst = _offset; + *((unsigned int *)dst) = *((unsigned int *)(dst + offset)); + dst += _clip.getX(); + *((unsigned int *)dst) = *((unsigned int *)(dst + offset)); + dst += _clip.getX(); + *((unsigned int *)dst) = *((unsigned int *)(dst + offset)); + dst += _clip.getX(); + *((unsigned int *)dst) = *((unsigned int *)(dst + offset)); +#ifdef DEBUG_CLIPPER + } else { + _clippedBlock ++; +#endif + } + advanceBlock(); +} diff --git a/scumm/smush/blitter.h b/scumm/smush/blitter.h new file mode 100644 index 00000000000..3515ba0a202 --- /dev/null +++ b/scumm/smush/blitter.h @@ -0,0 +1,79 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __BLITTER_H_ +#define __BLITTER_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_CLIPPER +# define DEBUG_CLIPPER +# endif +#else +# ifdef DEBUG_CLIPPER +# error DEBUG_CLIPPER defined without DEBUG +# endif +#endif + +#include "rect.h" + +class Chunck; +/*! @brief class for handling blitting on a frame buffer + + This class allows to perform secure blitting to a frame buffer in several ways. + This means that clipping is performed, so that only the part that you want to modify can be modified. +*/ +class Blitter { +private: + char * _ptr; //!< This is the pointer to the start of the frame buffer + char * _offset; //!< This is the current pointer in the frame buffer + Point _clip; //!< This is the size of the frame buffer (width/height) + Rect _src; //!< This is the size and position of the destination rectangle + Point _cur; //!< This is the current position in the destination rectangle + bool _outside; //!< flag that is set to \c true when the blitter reach the end of the destination rectangle +#ifdef DEBUG_CLIPPER + int _clipped; + int _clippedBlock; +#endif +public: + /*! @brief constructor + + @param buffer the frame buffer to blit to + @param dstsize the size of the frame buffer + @param src the rectangle to blit to + */ + Blitter(char * buffer, const Point & dstsize, const Rect & src); + virtual ~Blitter(); + void blit(char *, unsigned int); //!< This method allows to blit directly some data from a buffer + void blit(Chunck &, unsigned int); //!< This method allows to blit directly some data from a chunck + void put(char); //!< This method allows to blit one byte + void put(char, unsigned int); //!< This method allows to blit one byte several times + void advance(int = 1, int = 0); //!< This method allows to advance the current position in the blitter + void advanceBlock(int = 1, int = 0); //!< This method allows to advance the current position in the blitter in terms of blocks + void putBlock(unsigned int); //!< This method allows to blit one block from an int value repeated 4 time + void putBlock(Chunck &); //!< This method allows to blit one block directly read from a chunck + void putBlock(unsigned char *); //!< This method allows to blit one block directly from a buffer + void putBlock(unsigned int, unsigned int, unsigned int, unsigned int); //!< This method allows to blit one block from a 4 int value + void blockCopy(int); //!< This method allows to copy one block from another separated by the given offset +}; + +#endif diff --git a/scumm/smush/brenderer.cpp b/scumm/smush/brenderer.cpp new file mode 100644 index 00000000000..1efa8be5b0d --- /dev/null +++ b/scumm/smush/brenderer.cpp @@ -0,0 +1,75 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "brenderer.h" + +#include + +void BaseRenderer::clean() { + if(_data) { + delete[] _data; + _data = 0; + _width = _height = 0; + } +} + +BaseRenderer::BaseRenderer() : + _data(0), + _frame(0), + _nbframes(0), + _width(0), + _height(0) { +} + +BaseRenderer::~BaseRenderer() { + clean(); +} + +bool BaseRenderer::initFrame(const Point & p) { + clean(); + _width = p.getX(); + _height = p.getY(); + assert(_width && _height); + _data = new char[_width * _height]; + if(!_data) error("base_renderer unable to allocate frame buffer"); + return true; +} + +char * BaseRenderer::lockFrame(int frame) { + _frame = frame; + if(!_data) error("no allocated image buffer in lock_frame"); + return _data; +} + +bool BaseRenderer::unlockFrame() { + return true; +} + +bool BaseRenderer::flipFrame() { + save(); + return true; +} + +bool BaseRenderer::setPalette(const Palette & pal) { + _pal = pal; + return true; +} diff --git a/scumm/smush/brenderer.h b/scumm/smush/brenderer.h new file mode 100644 index 00000000000..792fd034c4e --- /dev/null +++ b/scumm/smush/brenderer.h @@ -0,0 +1,86 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __BRENDERER_H_ +#define __BRENDERER_H_ + +#include "config.h" + +#include "renderer.h" +#include "palette.h" +#include "rect.h" + +/*! @brief base class for easily creating ::renderer instances + + This class implements some function available in the ::renderer abstract class, so that + creation of subclasses of ::renderer is easier. +*/ +class BaseRenderer : public Renderer { +private: + Palette _pal; //!< The current palette + char * _data; //!< The current frame buffer + int _frame; //!< The current frame number + int _nbframes; //!< The number of frames in the animation + int _width; //!< The current frame's width + int _height; //!< The current frame's height + const char * _fname; //!< The filename of the animation being played +protected: + virtual void save(int frame = -1) = 0; + +protected: + const char * getFilename() const { return _fname; }; //!< accessor for animation filename + int getNbframes() const { return _nbframes; }; //!< accessor for number of frames + int getWidth() const { return _width; }; //!< accessor for current width + int getHeight() const { return _height; }; //!< accessor for current height + const Palette & pal() const { return _pal; }; //!< accessor for current palette + const char * data() const { return _data; }; //!< accessor for current frame buffer + void clean(); //!< memory cleanup (deletes frame buffer) + void setFrame(int f) { _frame = f; }; //!< allows to change the frame number +public: + int getFrame() const { return _frame; }; //!< accessor for current frame number + BaseRenderer(); + virtual ~BaseRenderer(); + + virtual bool initFrame(const Point & size); + virtual char * lockFrame(int frame); + virtual bool unlockFrame(); + virtual bool flipFrame(); + virtual bool setPalette(const Palette & pal); + virtual bool startDecode(const char * fname, int version, int nbframes) { _fname = fname; _nbframes = nbframes; return true; } + virtual Mixer * getMixer() { return 0; }; + virtual bool prematureClose() { return false; }; +}; + +/*! @brief A null ::renderer + + This class completely implements ::renderer, without actually doing anything. + This class is useful for performance measurements. +*/ +class NullRenderer : public BaseRenderer { +protected: + void save(int frame = -1) {}; +public: + NullRenderer() {}; + virtual ~NullRenderer() {}; + bool wait(int ms) { return true; }; +}; + +#endif diff --git a/scumm/smush/channel.h b/scumm/smush/channel.h new file mode 100644 index 00000000000..5010c3f5815 --- /dev/null +++ b/scumm/smush/channel.h @@ -0,0 +1,157 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CHANNEL_H_ +#define __CHANNEL_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_CHANNEL +# define DEBUG_CHANNEL +# endif +#else +# ifdef DEBUG_CHANNEL +# error DEBUG_CHANNEL defined without DEBUG +# endif +#endif + +class Chunck; +class ContChunck; + +/*! @brief interface for a sound channel (a track) + + This is the interface for sound channels. +*/ +class _Channel { +public: + virtual ~_Channel() {}; + // called by the smush_player + virtual bool appendData(Chunck & b, int size) = 0; + virtual bool setParameters(int, int, int, int) = 0; + virtual bool checkParameters(int, int, int, int, int) = 0; + // called by the mixer + virtual bool isTerminated() const = 0; + virtual int availableSoundData() const = 0; + virtual void getSoundData(short * sound_buffer, int size) = 0; // size is in sample + virtual void getSoundData(char * sound_buffer, int size) = 0; + virtual bool getParameters(int &rate, bool &stereo, bool &is_16bit) = 0; + virtual int getTrackIdentifier() const = 0; +}; + +class SaudChannel : public _Channel { +private: + int _track; //!< The track identifier + int _nbframes; //!< number of frames of the track (unused) + int _dataSize; //!< the size of the sound buffer + int _frequency; //!< the frequency target of the track (always 22050) + bool _inData; //!< are we processing data ? + bool _markReached; //!< set to \c true when the SMRK tag is reached + int _flags; //!< current flags of the track (unused) + int _volume; //!< the current track volume + int _balance; //!< the current track balance + int _index; //!< the current PSAD index (for coherency checking) + short _voltable[2][256]; //!< the precalculated volume table (stereo 16 bits) + unsigned char * _tbuffer; //!< data temporary buffer + int _tbufferSize; //!< temporary buffer size + unsigned char * _sbuffer; //!< sound buffer + int _sbufferSize; //!< sound buffer size + +protected: + void handleStrk(Chunck & c); + void handleSmrk(Chunck & c); + void handleShdr(Chunck & c); + bool handleSubTags(int & offset); + bool processBuffer(); + void recalcVolumeTable(); + +public: + SaudChannel(int track, int freq); + virtual ~SaudChannel(); + bool isTerminated() const; + bool setParameters(int duration, int flags, int vol1, int vol2); + bool checkParameters(int index, int duration, int flags, int vol1, int vol2); + bool appendData(Chunck & b, int size); + int availableSoundData() const; + void getSoundData(short * sound_buffer, int size); + void getSoundData(char * sound_buffer, int size) { error("16bit request for SAUD channel should never happen"); }; + bool getParameters(int &rate, bool &stereo, bool &is_16bit) { + rate = _frequency; + stereo = true; + is_16bit = true; + return true; + }; + virtual int getTrackIdentifier() const { return _track; }; +}; + +/*! @brief class for a IACT sound ::channel (a The Dig track) + + This class implements a channel specifically for The Dig. + + \bug for unknown reason, some sound have a too long duration, or repeat themselves. +*/ +class ImuseChannel : public _Channel { +private: + int _track; //!< the track number + unsigned char * _tbuffer; //!< data temporary buffer + int _tbufferSize; //!< temporary buffer size + unsigned char * _sbuffer; //!< sound buffer + int _sbufferSize; //!< sound buffer size + int _srbufferSize; + int _frequency; //!< the target frequency of the ::mixer + int _dataSize; //!< remaining size of sound data in the iMUS buffer + bool _inData; + + int _bitsize; //!< the bitsize of the original data + int _rate; //!< the sampling rate of the original data + int _channels; //!< the number of channels of the original data + +protected: + int decode(int size, int &ret); + void decode(); + bool processBuffer(); + bool handleMap(Chunck &); + bool handleFormat(Chunck &); + bool handleText(Chunck &); + bool handleRegion(Chunck &); + bool handleStop(Chunck &); + bool handleSubTags(int & offset); + +public: + ImuseChannel(int track, int freq); + virtual ~ImuseChannel(); + bool isTerminated() const; + bool setParameters(int nbframes, int size, int unk1, int unk2); + bool checkParameters(int index, int nbframes, int size, int unk1, int unk2); + bool appendData(Chunck & b, int size); + int availableSoundData() const; + void getSoundData(short * sound_buffer, int size); + void getSoundData(char * sound_buffer, int size); + bool getParameters(int &rate, bool &stereo, bool &is_16bit) { + rate = _frequency; + stereo = (_channels == 2); + is_16bit = (_bitsize > 8); + return true; + }; + virtual int getTrackIdentifier() const { return _track; }; +}; + +#endif diff --git a/scumm/smush/chunck.cpp b/scumm/smush/chunck.cpp new file mode 100644 index 00000000000..b4bf99fcbc9 --- /dev/null +++ b/scumm/smush/chunck.cpp @@ -0,0 +1,288 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "chunck.h" + +#include // for FILE, fopen, fclose, fseek and ftell +#include // for memcpy + +/*! @brief very small and fast wrapper for a ifstream. + + implements reference counting, so that ::file_chunck does not leak memory ! +*/ +class FilePtr { + char * _filename; + FILE * _ifs; + int _refcount; + int _curPos; +public: + FilePtr(const char * fname) : _refcount(1), _curPos(0) { + debug(9, "FilePtr created for %s", fname); + _filename = strdup(fname); + _ifs = fopen(fname, "rb"); + if(_ifs == NULL) error("FilePtr unable to read file \"%s\"", fname); + } + ~FilePtr() { + debug(9, "FilePtr destroyed for %s", _filename); + free(_filename); + fclose(_ifs); + } + int tell() { + return _curPos; + } + bool seek(int pos) { + if(pos != _curPos) { + fseek(_ifs, pos, SEEK_SET); + _curPos = pos; + } + return true; + } + bool read(void * ptr, int size) { + fread(ptr, size, 1, _ifs); + _curPos += size; + return true; + } + void incRef() { + _refcount++; + } + void decRef() { + if(--_refcount == 0) + delete this; + } +}; + +const char * Chunck::ChunckString(Chunck::type t) { + static char data[5]; + data[0] = (char)((t >> 24) & 0xFF); + data[1] = (char)((t >> 16) & 0xFF); + data[2] = (char)((t >> 8) & 0xFF); + data[3] = (char)((t >> 0) & 0xFF); + data[4] = 0; + return data; +} + +FileChunck::FileChunck() : _data(0), _type(0), _size(0), _curPos(0) { +} + +FileChunck::~FileChunck() { + if(_data) _data->decRef(); +} + +FileChunck::FileChunck(const char * fname) { + _data = new FilePtr(fname); + _data->read(&_type, 4); + _type = TO_BE_32(_type); + _data->read(&_size, 4); + _size = TO_BE_32(_size); + _offset = _data->tell(); + _curPos = 0; +} + +Chunck::type FileChunck::getType() const { + return _type; +} + +unsigned int FileChunck::getSize() const { + return _size; +} + +Chunck * FileChunck::subBlock() { + FileChunck * ptr = new FileChunck; + ptr->_data = _data; + _data->incRef(); + _data->seek(_offset + _curPos); + unsigned int temp; + _data->read(&temp, 4); + ptr->_type = TO_BE_32(temp); + _data->read(&temp, 4); + ptr->_size = TO_BE_32(temp); + ptr->_offset = _offset + _curPos + 8; + ptr->_curPos = 0; + seek(8 + ptr->getSize()); + return ptr; +} + +bool FileChunck::eof() const { + return _curPos >= _size; +} + +unsigned int FileChunck::tell() const { + return _curPos; +} + +bool FileChunck::seek(int delta, seek_type dir) { + switch(dir) { + case seek_cur: + _curPos += delta; + break; + case seek_start: + if(delta < 0) error("invalid seek request"); + _curPos = (unsigned int)delta; + break; + case seek_end: + if(delta > 0 || (_size + delta) < 0) error("invalid seek request"); + _curPos = (unsigned int)(_size + delta); + break; + } + if(_curPos > _size) { + error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta); + } + return true; +} + +bool FileChunck::read(void * buffer, unsigned int size) { + if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request"); + _data->seek(_offset + _curPos); + _data->read(buffer, size); + _curPos += size; + return true; +} + +char FileChunck::getChar() { + if(_curPos >= _size) error("invalid char read request"); + _data->seek(_offset + _curPos); + char buffer; + _data->read(&buffer, sizeof(buffer)); + _curPos+= sizeof(buffer); + return buffer; +} + +unsigned char FileChunck::getByte() { + if(_curPos >= _size) error("invalid byte read request"); + _data->seek(_offset + _curPos); + unsigned char buffer; + _data->read(&buffer, sizeof(buffer)); + _curPos+= sizeof(buffer); + return buffer; +} + +short FileChunck::getShort() { + unsigned short buffer = getWord(); + return *((short*)&buffer); +} + +unsigned short FileChunck::getWord() { + if(_curPos >= _size - 1) error("invalid word read request"); + _data->seek(_offset + _curPos); + unsigned short buffer; + _data->read(&buffer, sizeof(buffer)); + _curPos+= sizeof(buffer); + return TO_LE_16(buffer); +} + +unsigned int FileChunck::getDword() { + if(_curPos >= _size - 3) error("invalid dword read request"); + _data->seek(_offset + _curPos); + unsigned int buffer; + _data->read(&buffer, sizeof(buffer)); + _curPos+= sizeof(buffer); + return TO_LE_32(buffer); +} + +ContChunck::ContChunck(char * data) { + if(data == 0) error("Chunck() called with NULL pointer"); + _type = (Chunck::type)READ_BE_UINT32(data); + _size = READ_BE_UINT32(data+4); + _data = data + sizeof(Chunck::type) + sizeof(unsigned int); + _curPos = 0; +} + +Chunck::type ContChunck::getType() const { + return _type; +} + +unsigned int ContChunck::getSize() const { + return _size; +} + +Chunck * ContChunck::subBlock() { + ContChunck * ptr = new ContChunck(_data + _curPos); + seek(sizeof(Chunck::type) + sizeof(unsigned int) + ptr->getSize()); + return ptr; +} + +bool ContChunck::eof() const { + return _curPos >= _size; +} + +unsigned int ContChunck::tell() const { + return _curPos; +} + +bool ContChunck::seek(int delta, seek_type dir) { + switch(dir) { + case seek_cur: + _curPos += delta; + break; + case seek_start: + if(delta < 0) error("invalid seek request"); + _curPos = (unsigned int)delta; + break; + case seek_end: + if(delta > 0 || (_size + delta) < 0) error("invalid seek request"); + _curPos = (unsigned int)(_size + delta); + break; + } + if(_curPos > _size) { + error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta); + } + return true; +} + +bool ContChunck::read(void * buffer, unsigned int size) { + if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request"); + memcpy(buffer, _data + _curPos, size); + _curPos += size; + return true; +} + +char ContChunck::getChar() { + if(_curPos >= _size) error("invalid char read request"); + return _data[_curPos++]; +} + +unsigned char ContChunck::getByte() { + if(_curPos >= _size) error("invalid byte read request"); + unsigned char * ptr = (unsigned char *)(_data + _curPos); + _curPos += 1; + return *ptr; +} + +short ContChunck::getShort() { + if(_curPos >= _size - 1) error("invalid short read request"); + unsigned short buffer = getWord(); + return *((short*)&buffer); +} + +unsigned short ContChunck::getWord() { + if(_curPos >= _size - 1) error("invalid word read request"); + unsigned short * ptr = (unsigned short *)(_data + _curPos); + _curPos += 2; + return READ_LE_UINT16(ptr); +} + +unsigned int ContChunck::getDword() { + if(_curPos >= _size - 3) error("invalid dword read request"); + unsigned int * ptr = (unsigned int *)(_data + _curPos); + _curPos += 4; + return READ_LE_UINT32(ptr); +} diff --git a/scumm/smush/chunck.h b/scumm/smush/chunck.h new file mode 100644 index 00000000000..3a1ec6addac --- /dev/null +++ b/scumm/smush/chunck.h @@ -0,0 +1,121 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CHUNCK_H_ +#define __CHUNCK_H_ + +#include "config.h" + +/*! @brief Interface for chunck handling + + This class is an interface for reading from a chunck. + + \todo handle big endian system. +*/ +class Chunck { +public: + enum seek_type { seek_start, seek_end, seek_cur }; + virtual ~Chunck() {}; + typedef unsigned int type; //!< type of a chunck (i.e. The first 4byte field of the chunck structure). + /*! @brief convert a type to a string + + Utility function that convert a type to a string. + + @param t the type to convert to a string + + @return the converted string + */ + static const char * ChunckString(type t); + + virtual type getType() const = 0; //!< return the type of the chunck + virtual unsigned int getSize() const = 0; //!< return the size of the chunck + virtual Chunck * subBlock() = 0; //!< extract a subchunck from the current read position + virtual bool eof() const = 0; //!< is the chunck completely read ? + virtual unsigned int tell() const = 0; //!< get the chunck current read position + virtual bool seek(int delta, seek_type dir = seek_cur) = 0; //!< move the current read position inside the chunck + virtual bool read(void * buffer, unsigned int size) = 0; //!< read some data for the current read position + virtual char getChar() = 0; //!< extract the character at the current read position + virtual unsigned char getByte() = 0; //!< extract the byte at the current read position + virtual short getShort() = 0; //!< extract the short at the current read position + virtual unsigned short getWord() = 0; //!< extract the word at the current read position + virtual unsigned int getDword()= 0; //!< extract the dword at the current read position +}; + +class FilePtr; + +/*! @brief file based ::chunck + + This class is an implementation of ::chunck that handles file. + +*/ +class FileChunck : public Chunck { +private: + FilePtr * _data; + type _type; + unsigned int _size; + unsigned int _offset; + unsigned int _curPos; +protected: + FileChunck(); +public: + FileChunck(const char * fname); + virtual ~FileChunck(); + type getType() const; + unsigned int getSize() const; + Chunck * subBlock(); + bool eof() const; + unsigned int tell() const; + bool seek(int delta, seek_type dir = seek_cur); + bool read(void * buffer, unsigned int size); + char getChar(); + unsigned char getByte(); + short getShort(); + unsigned short getWord(); + unsigned int getDword(); +}; + +/*! @brief memory based ::chunck + + This class is an implementation of ::chunck that handles a memory buffer. +*/ +class ContChunck : public Chunck { +private: + char * _data; + Chunck::type _type; + unsigned int _size; + unsigned int _curPos; +public: + ContChunck(char * data); + Chunck::type getType() const; + unsigned int getSize() const; + Chunck * subBlock(); + bool eof() const; + unsigned int tell() const; + bool seek(int delta, seek_type dir = seek_cur); + bool read(void * buffer, unsigned int size); + char getChar(); + unsigned char getByte(); + short getShort(); + unsigned short getWord(); + unsigned int getDword(); +}; + +#endif diff --git a/scumm/smush/chunck_type.h b/scumm/smush/chunck_type.h new file mode 100644 index 00000000000..e3e25961756 --- /dev/null +++ b/scumm/smush/chunck_type.h @@ -0,0 +1,57 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CHUNCK_TYPE_H +#define __CHUNCK_TYPE_H + +#include "chunck.h" + +#define MAKE_TYPE(a,b,c,d) (Chunck::type)( ((a) << 24) | ((b) << 16) | ((c) << 8) | (d) ) + +static const Chunck::type TYPE_ANIM = MAKE_TYPE('A', 'N', 'I', 'M'); +static const Chunck::type TYPE_AHDR = MAKE_TYPE('A', 'H', 'D', 'R'); +static const Chunck::type TYPE_FRME = MAKE_TYPE('F', 'R', 'M', 'E'); +static const Chunck::type TYPE_NPAL = MAKE_TYPE('N', 'P', 'A', 'L'); +static const Chunck::type TYPE_FOBJ = MAKE_TYPE('F', 'O', 'B', 'J'); +static const Chunck::type TYPE_PSAD = MAKE_TYPE('P', 'S', 'A', 'D'); +static const Chunck::type TYPE_TRES = MAKE_TYPE('T', 'R', 'E', 'S'); +static const Chunck::type TYPE_XPAL = MAKE_TYPE('X', 'P', 'A', 'L'); +static const Chunck::type TYPE_IACT = MAKE_TYPE('I', 'A', 'C', 'T'); +static const Chunck::type TYPE_STOR = MAKE_TYPE('S', 'T', 'O', 'R'); +static const Chunck::type TYPE_FTCH = MAKE_TYPE('F', 'T', 'C', 'H'); +static const Chunck::type TYPE_SKIP = MAKE_TYPE('S', 'K', 'I', 'P'); +static const Chunck::type TYPE_STRK = MAKE_TYPE('S', 'T', 'R', 'K'); +static const Chunck::type TYPE_SMRK = MAKE_TYPE('S', 'M', 'R', 'K'); +static const Chunck::type TYPE_SHDR = MAKE_TYPE('S', 'H', 'D', 'R'); +static const Chunck::type TYPE_SDAT = MAKE_TYPE('S', 'D', 'A', 'T'); +static const Chunck::type TYPE_SAUD = MAKE_TYPE('S', 'A', 'U', 'D'); +static const Chunck::type TYPE_iMUS = MAKE_TYPE('i', 'M', 'U', 'S'); +static const Chunck::type TYPE_FRMT = MAKE_TYPE('F', 'R', 'M', 'T'); +static const Chunck::type TYPE_TEXT = MAKE_TYPE('T', 'E', 'X', 'T'); +static const Chunck::type TYPE_REGN = MAKE_TYPE('R', 'E', 'G', 'N'); +static const Chunck::type TYPE_STOP = MAKE_TYPE('S', 'T', 'O', 'P'); +static const Chunck::type TYPE_MAP_ = MAKE_TYPE('M', 'A', 'P', ' '); +static const Chunck::type TYPE_DATA = MAKE_TYPE('D', 'A', 'T', 'A'); +static const Chunck::type TYPE_ETRS = MAKE_TYPE('E', 'T', 'R', 'S'); + +#undef MAKE_TYPE + +#endif diff --git a/scumm/smush/codec1.cpp b/scumm/smush/codec1.cpp new file mode 100644 index 00000000000..495b50404f7 --- /dev/null +++ b/scumm/smush/codec1.cpp @@ -0,0 +1,76 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "codec1.h" +#include "chunck.h" +#include "blitter.h" + +Codec1Decoder::~Codec1Decoder() { +} + +bool Codec1Decoder::decode(Blitter & dst, Chunck & src) { + int val; + int size_line; + int code, length; + int h, height = getRect().height(); + + for(h = 0; h < height; h++) { + size_line = src.getWord(); // size of compressed line ! +#ifdef DEBUG_CODEC1 + debug(7, "codec1 : h == %d, size_line == %d", h, size_line); +#endif + while(size_line > 0) { + code = src.getByte(); + size_line --; + length = (code >> 1) + 1; +#ifdef DEBUG_CODEC1 + debug(7, "codec1 : length == %d", length); +#endif + if(code & 1) { + val = src.getByte(); + size_line --; + if(val) dst.put(val, length); + else dst.advance(length); +#ifdef DEBUG_CODEC1 + debug(7, "codec1 : blitting %d times %d", length, val); +#endif + } else { + size_line -= length; +#ifdef DEBUG_CODEC1 + debug(7, "codec1 : blitting %d entries", length); +#endif + while(length--) { + val = src.getByte(); + if(val) dst.put(val); + else dst.advance(); + } + } + } + } +#ifdef DEBUG_CODEC1 + if(!src.eof()) { + int len = src.getSize() - src.tell(); + debug(7, "codec1: remaining length after decode == %d", len); + } +#endif + return true; +} diff --git a/scumm/smush/codec1.h b/scumm/smush/codec1.h new file mode 100644 index 00000000000..ae60518d6ad --- /dev/null +++ b/scumm/smush/codec1.h @@ -0,0 +1,48 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CODEC1_H_ +#define __CODEC1_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_CODEC1 +# define DEBUG_CODEC1 +# endif +#else +# ifdef DEBUG_CODEC1 +# error DEBUG_CODEC1 defined without DEBUG +# endif +#endif + +#include "decoder.h" + +/*! @brief ::decoder for codec 1 and 3. + +*/ +class Codec1Decoder : public Decoder { +public: + virtual ~Codec1Decoder(); + bool decode(Blitter &, Chunck &); +}; + +#endif diff --git a/scumm/smush/codec37.cpp b/scumm/smush/codec37.cpp new file mode 100644 index 00000000000..5adaa56d543 --- /dev/null +++ b/scumm/smush/codec37.cpp @@ -0,0 +1,436 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "codec37.h" +#include "chunck.h" +#include "blitter.h" + +#include +#include // for memset + +bool Codec37Decoder::initSize(const Point & p, const Rect & r) { + if(r.width() != getRect().width() && r.height() != getRect().height()) { + if( + (r.width() != 320 || r.height() != 200) && + (r.width() != 384 || r.height() != 242) && + (r.width() != 640 || r.height() != 480) + ) + return false; + Decoder::initSize(p, r); + clean(); + int frame_size = getRect().width() * getRect().height(); + _deltaSize = frame_size * 2 + DELTA_ADD * 4; + _deltaBuf = new unsigned char[_deltaSize]; + if(_deltaBuf == 0) error("unable to allocate decoder buffer"); + _deltaBufs[0] = _deltaBuf + DELTA_ADD; + _deltaBufs[1] = _deltaBuf + frame_size + DELTA_ADD * 3; + _offsetTable = new short[255]; + if(_offsetTable == 0) error("unable to allocate decoder offset table"); + _tableLastPitch = -1; + _tableLastIndex = -1; + return true; + } + return false; +} + +Codec37Decoder::Codec37Decoder() { + _deltaSize = 0; + _deltaBuf = 0; + _deltaBufs[0] = 0; + _deltaBufs[1] = 0; + _curtable = 0; + _offsetTable = 0; + _tableLastPitch = -1; + _tableLastIndex = -1; + _prevSeqNb = 32768; // Some invalid number +} + +void Codec37Decoder::clean() { + if(_offsetTable) { + delete []_offsetTable; + _offsetTable = 0; + _tableLastPitch = -1; + _tableLastIndex = -1; + } + if(_deltaBuf) { + delete []_deltaBuf; + _deltaSize = 0; + _deltaBuf = 0; + _deltaBufs[0] = 0; + _deltaBufs[1] = 0; + } +} + +Codec37Decoder::~Codec37Decoder() { + clean(); +} + +void Codec37Decoder::maketable(int pitch, int index) { + static const char maketable_bytes[] = { + 0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0, 13, 0, 21, 0, + -1, 0, -2, 0, -3, 0, -5, 0, -8, 0, -13, 0, -17, 0, -21, 0, + 0, 1, 1, 1, 2, 1, 3, 1, 5, 1, 8, 1, 13, 1, 21, 1, + -1, 1, -2, 1, -3, 1, -5, 1, -8, 1, -13, 1, -17, 1, -21, 1, + 0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 8, 2, 13, 2, 21, 2, + -1, 2, -2, 2, -3, 2, -5, 2, -8, 2, -13, 2, -17, 2, -21, 2, + 0, 3, 1, 3, 2, 3, 3, 3, 5, 3, 8, 3, 13, 3, 21, 3, + -1, 3, -2, 3, -3, 3, -5, 3, -8, 3, -13, 3, -17, 3, -21, 3, + 0, 5, 1, 5, 2, 5, 3, 5, 5, 5, 8, 5, 13, 5, 21, 5, + -1, 5, -2, 5, -3, 5, -5, 5, -8, 5, -13, 5, -17, 5, -21, 5, + 0, 8, 1, 8, 2, 8, 3, 8, 5, 8, 8, 8, 13, 8, 21, 8, + -1, 8, -2, 8, -3, 8, -5, 8, -8, 8, -13, 8, -17, 8, -21, 8, + 0, 13, 1, 13, 2, 13, 3, 13, 5, 13, 8, 13, 13, 13, 21, 13, + -1, 13, -2, 13, -3, 13, -5, 13, -8, 13, -13, 13, -17, 13, -21, 13, + 0, 21, 1, 21, 2, 21, 3, 21, 5, 21, 8, 21, 13, 21, 21, 21, + -1, 21, -2, 21, -3, 21, -5, 21, -8, 21, -13, 21, -17, 21, -21, 21, + 0, -1, 1, -1, 2, -1, 3, -1, 5, -1, 8, -1, 13, -1, 21, -1, + -1, -1, -2, -1, -3, -1, -5, -1, -8, -1, -13, -1, -17, -1, -21, -1, + 0, -2, 1, -2, 2, -2, 3, -2, 5, -2, 8, -2, 13, -2, 21, -2, + -1, -2, -2, -2, -3, -2, -5, -2, -8, -2, -13, -2, -17, -2, -21, -2, + 0, -3, 1, -3, 2, -3, 3, -3, 5, -3, 8, -3, 13, -3, 21, -3, + -1, -3, -2, -3, -3, -3, -5, -3, -8, -3, -13, -3, -17, -3, -21, -3, + 0, -5, 1, -5, 2, -5, 3, -5, 5, -5, 8, -5, 13, -5, 21, -5, + -1, -5, -2, -5, -3, -5, -5, -5, -8, -5, -13, -5, -17, -5, -21, -5, + 0, -8, 1, -8, 2, -8, 3, -8, 5, -8, 8, -8, 13, -8, 21, -8, + -1, -8, -2, -8, -3, -8, -5, -8, -8, -8, -13, -8, -17, -8, -21, -8, + 0, -13, 1, -13, 2, -13, 3, -13, 5, -13, 8, -13, 13, -13, 21, -13, + -1, -13, -2, -13, -3, -13, -5, -13, -8, -13, -13, -13, -17, -13, -21, -13, + 0, -17, 1, -17, 2, -17, 3, -17, 5, -17, 8, -17, 13, -17, 21, -17, + -1, -17, -2, -17, -3, -17, -5, -17, -8, -17, -13, -17, -17, -17, -21, -17, + 0, -21, 1, -21, 2, -21, 3, -21, 5, -21, 8, -21, 13, -21, 21, -21, + -1, -21, -2, -21, -3, -21, -5, -21, -8, -21, -13, -21, -17, -21, 0, 0, + -8, -29, 8, -29, -18, -25, 17, -25, 0, -23, -6, -22, 6, -22, -13, -19, + 12, -19, 0, -18, 25, -18, -25, -17, -5, -17, 5, -17, -10, -15, 10, -15, + 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11, + 2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9, + 1, -9, 6, -9, -29, -8, -11, -8, -8, -8, -3, -8, 3, -8, 8, -8, + 11, -8, 29, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6, + -9, -6, -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6, + 22, -6, -17, -5, -7, -5, -4, -5, -2, -5, 0, -5, 2, -5, 4, -5, + 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -1, -4, 0, -4, + 1, -4, 3, -4, 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, -4, -3, + -3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2, -3, 4, -3, 6, -3, + 8, -3, -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, -1, -2, 0, -2, + 1, -2, 2, -2, 3, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, + -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, + 4, -1, 6, -1, 9, -1, -31, 0, -23, 0, -18, 0, -14, 0, -11, 0, + -7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -31, 1, 0, + 2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0, + 23, 0, 31, 0, -9, 1, -6, 1, -4, 1, -3, 1, -2, 1, -1, 1, + 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 6, 1, 9, 1, -11, 2, + -7, 2, -5, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, + 3, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, -4, 3, -2, 3, + -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 6, 3, 8, 3, + -13, 4, -10, 4, -5, 4, -3, 4, -1, 4, 0, 4, 1, 4, 3, 4, + 5, 4, 10, 4, 13, 4, -17, 5, -7, 5, -4, 5, -2, 5, 0, 5, + 2, 5, 4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, + -1, 6, 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, + 0, 7, 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, -3, 8, 3, 8, + 8, 8, 11, 8, 29, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, + -4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11, + 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17, + 5, 17, 25, 17, -25, 18, 0, 18, -12, 19, 13, 19, -6, 22, 6, 22, + 0, 23, -17, 25, 18, 25, -8, 29, 8, 29, 0, 31, 0, 0, -6, -22, + 6, -22, -13, -19, 12, -19, 0, -18, -5, -17, 5, -17, -10, -15, 10, -15, + 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11, + 2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9, + 1, -9, 6, -9, -11, -8, -8, -8, -3, -8, 0, -8, 3, -8, 8, -8, + 11, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6, -9, -6, + -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6, 22, -6, + -17, -5, -7, -5, -4, -5, -2, -5, -1, -5, 0, -5, 1, -5, 2, -5, + 4, -5, 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -2, -4, + -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 5, -4, 10, -4, 13, -4, + -8, -3, -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3, + 2, -3, 3, -3, 4, -3, 6, -3, 8, -3, -11, -2, -7, -2, -5, -2, + -4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 3, -2, + 4, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, -5, -1, -4, -1, + -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, + 5, -1, 6, -1, 9, -1, -23, 0, -18, 0, -14, 0, -11, 0, -7, 0, + -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -23, 1, 0, 2, 0, + 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0, 23, 0, + -9, 1, -6, 1, -5, 1, -4, 1, -3, 1, -2, 1, -1, 1, 0, 1, + 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 9, 1, -11, 2, + -7, 2, -5, 2, -4, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, + 2, 2, 3, 2, 4, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, + -4, 3, -3, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, + 4, 3, 6, 3, 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, -2, 4, + -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 5, 4, 10, 4, 13, 4, + -17, 5, -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 1, 5, 2, 5, + 4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6, + 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0, 7, + 2, 7, 5, 7, -11, 8, -8, 8, -3, 8, 0, 8, 3, 8, 8, 8, + 11, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, -4, 10, 4, 10, + 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11, 19, 12, -19, 13, + -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17, 5, 17, 0, 18, + -12, 19, 13, 19, -6, 22, 6, 22, 0, 23, + }; + + if (_tableLastPitch == pitch && _tableLastIndex == index) + return; +#ifdef DEBUG_CODEC37 + debug(7, "codec37::maketable(%d, %d) called", pitch, index); +#endif + _tableLastPitch = pitch; + _tableLastIndex = index; + index *= 255; + assert(index + 254 < (int)(sizeof(maketable_bytes) / 2)); + + for (int i = 0; i < 255; i++) { + int j = (i + index) << 1; // * 2 + _offsetTable[i] = maketable_bytes[j + 1] * pitch + maketable_bytes[j]; + } +} + +void Codec37Decoder::proc1(Blitter & dst, Chunck & src, int next_offs, int bw, int bh, int size) { + unsigned char * decoded = new unsigned char[size]; + int w = 0; + while(!src.eof()) { + int code = src.getByte(); + int length = (code >> 1) + 1; + if (code & 1) { + unsigned char val = src.getByte(); + while(length--) + decoded[w++] = val; + } else { + while(length--) { + decoded[w++] = src.getByte(); + } + } + } + assert(w == size); + w = 0; + // Now we have our stream ready... + for(int i = 0; i < size; i++) { + if(decoded[i] == 0xFF) { + dst.putBlock(decoded + i + 1); + i += 16; + } else { + dst.blockCopy(_offsetTable[decoded[i]] + next_offs); + } + if(++w == bw) { + w = 0; + dst.advance(0, 3); + } + } + delete []decoded; +} + +void Codec37Decoder::proc2(Blitter & dst, Chunck & src, int size) { // This is codec1 like... +#ifdef DEBUG_CODEC37_PROC2 + int decoded_size = 0; + int coded_size = 0; +#endif + do { + int code = src.getByte(); + int length = (code >> 1) + 1; + size -= length; +#ifdef DEBUG_CODEC37_PROC2 + decoded_size += length; + coded_size += 1 + ((code & 1) ? 1 : length); + + debug(7, "proc2() : code == %d : length == %d : decoded_size == %d : coded_size == %d : seek - header == %d : size == %d", + code, length, decoded_size, coded_size, src.tell() - 31, size + decoded_size); +#endif + if (code & 1) + dst.put(src.getChar(), length); + else + // while(length--) dst.put(src.get_char()); + dst.blit(src, length); + } while (size); +} + +void Codec37Decoder::proc3WithFDFE(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) { + do { + int i = bw; + do { + int code = src.getByte(); + if (code == 0xFD) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(1)); +#else + dst.putBlock(expand(src.getByte())); +#endif + } else if (code == 0xFE) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(2)); +#else + dst.putBlock(expand(src.getByte()), expand(src.getByte()), expand(src.getByte()), expand(src.getByte())); +#endif + } else if (code == 0xFF) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(3)); +#else + dst.putBlock(src); +#endif + } else { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(4)); +#else + dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset ! +#endif + } + } while (--i); + dst.advance(0, 3); // advance 3 lines + } while (--bh); +} + +void Codec37Decoder::proc3WithoutFDFE(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) { + do { + int i = bw; + do { + int code = src.getByte(); + if (code == 0xFF) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(5)); +#else + dst.putBlock(src); +#endif + } else { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(6)); +#else + dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset ! +#endif + } + } while (--i); + dst.advance(0, 3); // advance 3 lines + } while (--bh); +} + +void Codec37Decoder::proc4(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) { +#ifdef DEBUG_CODEC37_PROC4 + int b_nb = 0; +#endif + do { + int i = bw; + do { + int code = src.getByte(); + if (code == 0xFD) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(7)); +#else + dst.putBlock(expand(src.getByte())); +#endif + } else if (code == 0xFE) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(8)); +#else + dst.putBlock(expand(src.getByte()), expand(src.getByte()), expand(src.getByte()), expand(src.getByte())); +#endif + } else if (code == 0xFF) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(9)); +#else + dst.putBlock(src); +#endif + } else if (code == 0x00) { + int length = src.getByte() + 1; + for (int l = 0; l < length; l++) { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(10)); +#else + dst.blockCopy(next_offs); +#endif + i--; + if (i == 0) { + dst.advance(0, 3); // advance 3 lines + bh--; + i = bw; + } + } + if(bh == 0) return; + i++; + } else { +#ifdef USE_COLOR_CODE_FOR_BLOCK + dst.putBlock(expand(11)); +#else + dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset ! +#endif + } + } while (--i); + dst.advance(0, 3); // advance 3 lines + } while (--bh); +} + +bool Codec37Decoder::decode(Blitter & dst, Chunck & src) { + int width = getRect().width(); + int height = getRect().height(); + int bw = (width + 3) >> 2, bh = (height + 3) >> 2; + int pitch = bw << 2; +#ifdef DEBUG_CODEC37 + debug(7, "codec37::decode() : width == %d : height == %d : pitch == %d : _prevSeqNb == %d", + width, height, pitch, _prevSeqNb); +#endif + int code = src.getByte(); // 0 -> 1 (1) + int index = src.getByte(); // 1 -> 2 (1) + unsigned short seq_nb = src.getWord(); // 2 -> 4 (2) + unsigned int decoded_size = src.getDword(); // 4 -> 8 (4) +#ifdef DEBUG_CODEC37 + unsigned int coded_size = src.getDword(); // 8 -> 12 (4) +#else + src.seek(4); +#endif + unsigned int mask_flag = src.getDword(); // 12 -> 16 (4) +#ifdef DEBUG_CODEC37 + debug(7, "codec37::decode() : code == %d : index == %d : seq_nb == %d : decoded_size == %d : coded_size == %d : mask_flag == %d", + code, index, seq_nb, decoded_size, coded_size, mask_flag); +#endif + maketable(pitch, index); + if(code == 3 || code == 4 || code == 1) { + assert(seq_nb && _prevSeqNb + 1 == seq_nb); + if (seq_nb & 1 || !(mask_flag & 1)) _curtable ^= 1; + } + Blitter blit((char *)_deltaBufs[_curtable], Point(width, height), Rect(0, 0, width, height)); + switch(code) { + case 0: + memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf); + memset(_deltaBufs[_curtable] + decoded_size, 0, _deltaBuf + _deltaSize - _deltaBufs[_curtable] - decoded_size); + blit.blit(src, decoded_size); + break; + case 1: + proc1(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh, decoded_size); + break; + case 2: + memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf); + memset(_deltaBufs[_curtable] + decoded_size, 0, _deltaBuf + _deltaSize - _deltaBufs[_curtable] - decoded_size); + proc2(blit, src, decoded_size); + break; + case 3: + if(mask_flag & 1) + proc3WithFDFE(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh); + else + proc3WithoutFDFE(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh); + break; + case 4: + proc4(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh); + break; + default: +#ifdef DEBUG_CODEC37 + error("codec37::decode() received an invalid code : %d", code); +#endif + break; + } + dst.blit((char*)_deltaBufs[_curtable], width * height); + _prevSeqNb = seq_nb; + return true; +} + diff --git a/scumm/smush/codec37.h b/scumm/smush/codec37.h new file mode 100644 index 00000000000..65fd7c11955 --- /dev/null +++ b/scumm/smush/codec37.h @@ -0,0 +1,86 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CODEC37_H_ +#define __CODEC37_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_CODEC37 +# define DEBUG_CODEC37 +# endif +#else +# ifdef DEBUG_CODEC37 +# error DEBUG_CODEC37 defined without DEBUG +# endif +#endif + +#ifdef DEBUG_CODEC37 +# ifndef NO_DEBUG_CODEC37_PROCS +# define DEBUG_CODEC37_PROC1 +# define DEBUG_CODEC37_PROC2 +# define DEBUG_CODEC37_PROC3 +# define DEBUG_CODEC37_PROC4 +# endif +#endif + +#include "decoder.h" + +/*! @brief ::decoder for codec 37. + +*/ + +#define DELTA_ADD 0x3E00 // what is this 0x3E00 ?? == 320*200/4 - 128 + // It looks like it is a safe-guarding protection from bugs., but maybe not... + +class Codec37Decoder : public Decoder { +private: + int _deltaSize; + unsigned char * _deltaBufs[2]; + unsigned char * _deltaBuf; + short * _offsetTable; + int _curtable; + unsigned short _prevSeqNb; + int _tableLastPitch; + int _tableLastIndex; + +public: + bool initSize(const Point &, const Rect &); + Codec37Decoder(); + void clean(); + virtual ~Codec37Decoder(); +protected: + static inline unsigned int expand(unsigned char b) { + unsigned int r = b | (b << 8); + return r | (r << 16); + } + void maketable(int, int); + void proc1(Blitter &, Chunck &, int, int, int, int); + void proc2(Blitter &, Chunck &, int); + void proc3WithFDFE(Blitter &, Chunck &, int, int, int); + void proc3WithoutFDFE(Blitter &, Chunck &, int, int, int); + void proc4(Blitter &, Chunck &, int, int, int); +public: + bool decode(Blitter &, Chunck &); +}; + +#endif diff --git a/scumm/smush/codec44.cpp b/scumm/smush/codec44.cpp new file mode 100644 index 00000000000..9795842e768 --- /dev/null +++ b/scumm/smush/codec44.cpp @@ -0,0 +1,71 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "codec44.h" +#include "chunck.h" +#include "blitter.h" + +bool Codec44Decoder::decode(Blitter & dst, Chunck & src) { + int size_line; + int num; + int w, width = getRect().width() + 1; + int h, height = getRect().height() + 1; + bool zero; +#ifdef DEBUG_CODEC44 + debug(7, "codec44 : %dx%d", width, height); +#endif + + for(h = 0; h < height - 1; h++) { + w = width; + size_line = src.getWord(); // size of compressed line ! +#ifdef DEBUG_CODEC44 + debug(7, "codec44 : h == %d, size_line == %d", h, size_line); +#endif + zero = true; + while(size_line > 1) { + num = src.getWord(); + size_line -= 2; + if(zero) { +#ifdef DEBUG_CODEC44 + debug(7, "codec44 : zeroing %d, entries", num); +#endif + if(w == num) + num--; + w -= num; + if(num) + dst.put(0, num); + } else { + num += 1; +#ifdef DEBUG_CODEC44 + debug(7, "codec44 : blitting %d, entries", num); +#endif + if(w == num) + num--; + w -= num; + dst.blit(src, num); + size_line -= num; + } + zero = !zero; + } + } + return true; +} diff --git a/scumm/smush/codec44.h b/scumm/smush/codec44.h new file mode 100644 index 00000000000..a7c39b02fbf --- /dev/null +++ b/scumm/smush/codec44.h @@ -0,0 +1,47 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CODEC44_H_ +#define __CODEC44_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_CODEC44 +# define DEBUG_CODEC44 +# endif +#else +# ifdef DEBUG_CODEC44 +# error DEBUG_CODEC44 defined without DEBUG +# endif +#endif + +#include "decoder.h" + +/*! @brief ::decoder for codec 21 and 44. + +*/ +class Codec44Decoder : public Decoder { +public: + bool decode(Blitter & dst, Chunck & src); +}; + +#endif diff --git a/scumm/smush/codec47.cpp b/scumm/smush/codec47.cpp new file mode 100644 index 00000000000..88038bb94d9 --- /dev/null +++ b/scumm/smush/codec47.cpp @@ -0,0 +1,51 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "codec47.h" +#include "chunck.h" +#include "blitter.h" + +DumpDecoder::~DumpDecoder() { +} + +bool DumpDecoder::decode(Blitter & dst, Chunck & src) { + int n = 0, i = 0; + int seq = src.getWord(); + int codec = src.getByte(); + int flags = src.getByte(); + int unknown[22]; + for(i = 0; i < 0; i++) { + unknown[i] = src.getByte(); + } + if(codec == 5 || codec == 1) { + do { + int code = src.getByte(); + int length = (code >> 1) + 1; + if (code & 1) + dst.put(src.getChar(), length); + else + dst.blit(src, length); + } while (!src.eof()); + } + + return true; +} diff --git a/scumm/smush/codec47.h b/scumm/smush/codec47.h new file mode 100644 index 00000000000..ecf34f7e705 --- /dev/null +++ b/scumm/smush/codec47.h @@ -0,0 +1,38 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CODEC_47_H_ +#define __CODEC_47_H_ + +#include "config.h" + +#include "decoder.h" + +/*! @brief ::decoder for debugging purpose. + +*/ +class DumpDecoder : public Decoder { +public: + virtual ~DumpDecoder(); + bool decode(Blitter &, Chunck &); +}; + +#endif diff --git a/scumm/smush/color.cpp b/scumm/smush/color.cpp new file mode 100644 index 00000000000..e88785ccbdc --- /dev/null +++ b/scumm/smush/color.cpp @@ -0,0 +1,69 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "color.h" + +Color::Color() : _r(0), _g(0), _b(0) { +} + +Color::Color(value_type r, value_type g, value_type b) : _r(r), _g(g), _b(b) { +} + +Color::Color(const Color & c) : _r(c._r), _g(c._g), _b(c._b) { +} + +Color & Color::operator=(const Color & c) { + _r = c._r; + _g = c._g; + _b = c._b; + return *this; +} + +Color::~Color() { +} + +Color::value_type Color::red() const { + return _r; +} + +Color::value_type Color::green() const { + return _g; +} + +Color::value_type Color::blue() const { + return _b; +} + +void Color::delta(short * ptr) { + // This is a very specific method for XPALs. + int t; +#define UPDATE_COLOR(c, inc) (((int)((c)) << 7) + (c) + (inc)) >> 7 +#define CHECK_BOUNDS(c) (((c) > 255) ? 255 : (((c) < 0) ? 0 : (c))) + t = UPDATE_COLOR(_r, ptr[0]); + _r = CHECK_BOUNDS(t); + t = UPDATE_COLOR(_g, ptr[1]); + _g = CHECK_BOUNDS(t); + t = UPDATE_COLOR(_b, ptr[2]); + _b = CHECK_BOUNDS(t); +#undef UPDATE_COLOR +#undef CHECK_BOUNDS +} diff --git a/scumm/smush/color.h b/scumm/smush/color.h new file mode 100644 index 00000000000..00c89781621 --- /dev/null +++ b/scumm/smush/color.h @@ -0,0 +1,57 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __COLOR_H_ +#define __COLOR_H_ + +#include "config.h" + +/*! @brief simple class for handling a color. + + This small class is an helper for colors. +*/ +class Color { +public: + typedef unsigned char value_type; //!< The type of the color components. +private: + value_type _r; //!< The red component. + value_type _g; //!< The green component. + value_type _b; //!< The blue component. +public: + Color(); + Color(value_type, value_type, value_type); + Color(const Color &); + Color & operator=(const Color &); + virtual ~Color(); + value_type red() const; + value_type green() const; + value_type blue() const; + /*! @brief handle delta palette modification + + This method is used specifically by player::handleDeltaPalette(). + It updates the color component using delta values given as short. + + @param ptr pointer to a table of 3 shorts that contain delta values to use. + */ + void delta(short * ptr); +}; + +#endif diff --git a/scumm/smush/config.h b/scumm/smush/config.h new file mode 100644 index 00000000000..4734413f2eb --- /dev/null +++ b/scumm/smush/config.h @@ -0,0 +1,42 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +#include +#include + +#ifndef NDEBUG +#define DEBUG +#endif + +//~ #define NO_DEBUG_MIXER +//~ #define NO_DEBUG_CHANNEL +//~ #define NO_DEBUG_CLIPPER +#define NO_DEBUG_CODEC1 +#define NO_DEBUG_CODEC37 +#define NO_DEBUG_CODEC44 +//~ #define NO_DEBUG_WIN32 +//~ #define NO_DEBUG_FONT_RENDERER + + +#endif diff --git a/scumm/smush/decoder.h b/scumm/smush/decoder.h new file mode 100644 index 00000000000..a216d2b6b12 --- /dev/null +++ b/scumm/smush/decoder.h @@ -0,0 +1,51 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __DECODER_H_ +#define __DECODER_H_ + +#include "config.h" + +#include "rect.h" + +class Blitter; +class Chunck; + +/*! @brief base class for codec decompression. + + This class provides an interface for codec decompression. + +*/ +class Decoder { +private: + Rect _r; //!< current size of the frame object to decode + Point _p; //!< position of the frame object to decode +protected: + const Rect & getRect() const{ return _r; } + const Point & getSize() const { return _p; } +public: + Decoder() {}; + virtual ~Decoder() {}; + virtual bool initSize(const Point & p, const Rect & r) { _p = p; _r = r; return true; }; + virtual bool decode(Blitter &, Chunck &) = 0; +}; + +#endif diff --git a/scumm/smush/frenderer.cpp b/scumm/smush/frenderer.cpp new file mode 100644 index 00000000000..7f3f08cae8f --- /dev/null +++ b/scumm/smush/frenderer.cpp @@ -0,0 +1,232 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "frenderer.h" +#include "rect.h" + +#include +#include // for memcpy, strcat, strdup + +#ifndef max +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +FontRenderer::FontRenderer(bool use_original_colors) : _nbChars(0), _color(-1), _original(use_original_colors) { +} + +FontRenderer::~FontRenderer() { + for(int i = 0; i < _nbChars; i++) { + if(_chars[i].chr) delete []_chars[i].chr; + } +} + +void FontRenderer::save(int frame) { + _chars[_nbChars].width = getWidth(); + _chars[_nbChars].height = getHeight(); + int size = getWidth() * getHeight(); + _chars[_nbChars].chr = new char[size]; + memcpy(_chars[_nbChars].chr, data(), size); + _nbChars++; +} + +int FontRenderer::charWidth(int v) const { + if(v < 0) v = 256 + v; + if(v < 0 || v >= _nbChars) error("invalid character in FontRenderer::charWidth : %d (%d)", v, _nbChars); + return _chars[v].width; +} + +int FontRenderer::charHeight(int v) const { + if(v < 0) v = 256 + v; + if(v < 0 || v >= _nbChars) error("invalid character in FontRenderer::charHeight : %d (%d)", v, _nbChars); + return _chars[v].height; +} + +int FontRenderer::stringWidth(const char * str) const { + int ret = 0; + + while(*str) { + ret += charWidth(*str++); + } + + return ret; +} + +int FontRenderer::stringHeight(const char * str) const { + int ret = 0; + + for(int i = 0; str[i] != 0; i++) { + int h = charHeight(str[i]); + ret = max(ret, h); + } + + return ret; +} + +int FontRenderer::drawChar(char * buffer, const Point & size, int x, int y, int chr) const { + int w = _chars[chr].width; + int h = _chars[chr].height; + char * src = _chars[chr].chr; + char * dst = buffer + size.getX() * y + x; + + if(_original) { + for(int j = 0; j < h; j++) { + for(int i = 0; i < w; i++) { + int value = *src++; + if(value) dst[i] = value; + } + dst += size.getX(); + } + } else { + int color = (_color != -1) ? _color : 1; + for(int j = 0; j < h; j++) { + for(int i = 0; i < w; i++) { + int value = *src++; + if(value == 1) { + dst[i] = color; + } else if(value) { + dst[i] = 0; + } + } + dst += size.getX(); + } + } + return w; +} + +static char * * split(const char * str, char sep) { + char * * ret = new char *[32]; + int n = 0; + const char * i = str, * j = strchr(i, sep); + + while(j != NULL) { + assert(n < 30); + ret[n] = new char[j - i + 1]; + memcpy(ret[n], i, j - i); + ret[n++][j - i] = 0; + i = j+1; + j = strchr(i, sep); + } + + ret[n] = new char[strlen(i) + 1]; + memcpy(ret[n], i, strlen(i)); + ret[n++][strlen(i)] = 0; + ret[n] = 0; + return ret; +} + +void FontRenderer::drawSubstring(const unsigned char * str, char * buffer, const Point & size, int x, int y) const { + for(int i = 0; str[i] != 0; i++) + x += drawChar(buffer, size, x, y, str[i]); +} + +bool FontRenderer::drawStringAbsolute(const char * str, char * buffer, const Point & size, int x, int y) const { + debug(9, "FontRenderer::drawStringAbsolute(%s, %d, %d)", str, x, y); + while(str) { + char line[256]; + char * pos = strchr(str, '\n'); + if(pos) { + memcpy(line, str, pos - str - 1); + line[pos - str - 1] = 0; + str = pos + 1; + } else { + strcpy(line, str); + str = 0; + } + drawSubstring((const unsigned char *)line, buffer, size, x, y); + y += stringHeight(line); + } + return true; +} + +bool FontRenderer::drawStringCentered(const char * str, char * buffer, const Point & size, int y, int xmin, int width, int offset) const { + debug(9, "FontRenderer::drawStringCentered(%s, %d, %d)", str, xmin, y); + assert(strchr(str, '\n') == 0); + char * * words = split(str, ' '); + int nb_sub = 0; + + while(words[nb_sub]) nb_sub++; + + int * sizes = new int[nb_sub]; + int i = 0, max_width = 0, height = 0, nb_subs = 0; + + for(i = 0; i < nb_sub; i++) + sizes[i] = stringWidth(words[i]); + + char * * substrings = new char *[nb_sub]; + int * substr_widths = new int[nb_sub]; + int space_width = charWidth(' '); + + while(i < nb_sub) { + int substr_width = sizes[i]; + char * substr = new char[1000]; + strcpy(substr, words[i]); + int j = i + 1; + + while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) { + substr_width += sizes[j++] + space_width; + } + + for(int k = i + 1; k < j; k++) { + strcat(substr, " "); + strcat(substr, words[k]); + } + + substrings[nb_subs] = substr; + substr_widths[nb_subs++] = substr_width; + if(substr_width > max_width) + max_width = substr_width; + i = j; + height += stringHeight(substr); + } + + delete []sizes; + for(i = 0; i < nb_sub; i++) { + delete []words[i]; + } + delete []words; + + max_width = (max_width + 1) >> 1; + // we have a box from 0 -> max_width + // we want a box from (xmin + offset) - max_width / 2, (xmin + offset) + max_width / 2 + int x = xmin + width / 2; + x += offset - size.getX() / 2; + + if(x < max_width) x = max_width; + if(x + max_width > size.getX()) { + x = size.getX() - max_width; + } + + if(y + height > size.getY()) { + y = size.getY() - height; + } + + for(i = 0; i < nb_subs; i++) { + int substr_width = substr_widths[i]; + drawSubstring((const unsigned char *)substrings[i], buffer, size, x - substr_width / 2, y); + y += stringHeight(substrings[i]); + delete []substrings[i]; + } + + delete []substr_widths; + delete []substrings; + return true; +} diff --git a/scumm/smush/frenderer.h b/scumm/smush/frenderer.h new file mode 100644 index 00000000000..2ed9cd98cc3 --- /dev/null +++ b/scumm/smush/frenderer.h @@ -0,0 +1,164 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __FRENDERER_H_ +#define __FRENDERER_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_FONT_RENDERER +# define DEBUG_FONT_RENDERER +# endif +#else +# ifdef DEBUG_FONT_RENDERER +# error DEBUG_FONT_RENDERER defined without DEBUG +# endif +#endif + +#include "brenderer.h" +#include "rect.h" +#include "blitter.h" + +/*! @brief ::renderer implementation specifically designed for font files. + + This class is a valid ::renderer implementation. The frames are kept in memory, as bitmap representing characters, so that + they can be rendered again in another frame as strings. + + This class also contains some functions useful for printing strings. This is used to show subtitles and more generally texts + in animations. + + @todo update the mehod to use the ::blitter class, instead of direct pointers. +*/ +class FontRenderer : public BaseRenderer { +private: + int _nbChars; //!< The number of frames in the font + int _color; //!< A color parameter used for font printing. + bool _original; //!< flag for color selection + struct { + int width; + int height; + char * chr; + } _chars[256]; //!< array that contains the size of the different frames (i.e. characters) of the font. +public: + /*! @brief font_renderer constructor + + @param use_original_colors flag to indicate if the font use it's own color, or if the base color are set at runtime. + */ + FontRenderer(bool use_original_colors = false); + virtual ~FontRenderer(); + virtual bool wait(int ms) { return true; }; +protected: + virtual void save(int frame = -1); + /*! @brief get the width of a character. + + @param c the character we want the width from. + + @return the width of the character + */ + int charWidth(int c) const; + /*! @brief get the width of a string. + + @param str the string we want the width from. + + @return the complete width of the string + */ + int stringWidth(const char * str) const; + /*! @brief get the height of a character. + + @param c the character we want the height from. + + @return the height of the character + */ + int charHeight(int c) const; + /*! @brief get the height of a string. + + @param str the string we want the height from. + + @return the complete height of the string + */ + int stringHeight(const char * str) const; + /*! @brief draw a character in the given frame buffer. + + @param buffer the frame buffer to draw into. + @param size the size of the frame buffer. + @param x the horizontal position of the topleft corner of the character. + @param y the vertical position of the topleft corner of the character. + @param c the character to draw. + + @bug This method does not clip. This is not really a bug, as it should always be correctly called, but some asserts would be welcome. + + @return the width of the character + */ + int drawChar(char * buffer, const Point & size, int x, int y, int c) const; + /*! @brief draw a string in the given frame buffer. + + @param str the string to draw. + @param buffer the frame buffer to draw into. + @param size the size of the frame buffer. + @param x the horizontal position of the topleft corner of the string. + @param y the vertical position of the topleft corner of the string. + + @bug This method does not clip. This is not really a bug, as it should always be correctly called, but some asserts would be welcome. + */ + void drawSubstring(const unsigned char * str, char * buffer, const Point & size, int x, int y) const; +public: + /*! @brief change the programmable color of the font. + + @param c the new color to use. + + @return \c true if everything went fine, \c false otherwise + */ + bool setColor(int c) { _color = c; return true; } + /*! @brief draw a centered and possibly using multiple lines string. + + This method performs calculation of the string size before choosing where to draw it. + As I still not have figured out exactly what is the meaning of the fields in the TRES chunck, + the real meaning of the parameters can be quite difficult to understand. + + @remark The current implementation is incorrect in the sense that it does not conform to the original game. + @todo rewrite and rethink this to better match the original implementation. + + @param str the string to draw. + @param buffer the frame buffer to draw into. + @param size the size of the frame buffer. + @param y the vertical position of the topleft corner of the string. This position may be changed if it is too low to be correctly drawn. + @param xmin the minimum horizontal position of the topleft corner of the string. + @param width the maximum width of the string. If the string is too long, it will wrap. + @param offset offset to give to the horizontal position. + + @return \c true if everything went fine, \c false otherwise + */ + bool drawStringCentered(const char * str, char * buffer, const Point & size, int y, int xmin, int width, int offset) const; + /*! @brief draw a string at an absolute position. + + @param str the string to draw. + @param buffer the frame buffer to draw into. + @param size the size of the frame buffer. + @param x the horizontal position of the topleft corner of the string. + @param y the vertical position of the topleft corner of the string. This position may be changed if it is too low to be correctly drawn. + + @return \c true if everything went fine, \c false otherwise + */ + bool drawStringAbsolute(const char * str, char * buffer, const Point & size, int x, int y) const; +}; + +#endif diff --git a/scumm/smush/imuse_channel.cpp b/scumm/smush/imuse_channel.cpp new file mode 100644 index 00000000000..f082407abd0 --- /dev/null +++ b/scumm/smush/imuse_channel.cpp @@ -0,0 +1,329 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "channel.h" +#include "chunck.h" +#include "chunck_type.h" + +#include +#include // for memcpy.h +#ifndef min +#define min(x, y) ((x) > (y) ? (y) : (x)) +#endif + +ImuseChannel::ImuseChannel(int track, int freq) : + _track(track), + _tbuffer(0), + _tbufferSize(0), + _sbuffer(0), + _sbufferSize(0), + _frequency(freq), + _dataSize(-1), + _inData(false) { +} + +ImuseChannel::~ImuseChannel() { + if(_tbuffer) { + delete []_tbuffer; + } + if(_sbuffer) { + warning("_sbuffer should be 0 !!!"); + delete []_sbuffer; + } +} + +bool ImuseChannel::isTerminated() const { + return (_dataSize <= 0 && _sbuffer == 0); +} + +bool ImuseChannel::setParameters(int nbframes, int size, int unk1, int unk2) { + return true; +} + +bool ImuseChannel::checkParameters(int index, int nbframes, int size, int unk1, int unk2) { + return true; +} + +bool ImuseChannel::appendData(Chunck & b, int size) { + if(_dataSize == -1) { // First call + assert(size > 8); + Chunck::type imus_type = b.getDword(); imus_type = TO_BE_32(imus_type); + unsigned int imus_size = b.getDword(); imus_size = TO_BE_32(imus_size); + if(imus_type != TYPE_iMUS) error("Invalid CHUNCK for imuse_channel"); + size -= 8; + _tbufferSize = size; + assert(_tbufferSize); + _tbuffer = new unsigned char[_tbufferSize]; + if(!_tbuffer) error("imuse_channel failed to allocate memory"); + b.read(_tbuffer, size); + _dataSize = -2; // even if _in_data does not get set, this won't be called again + } else { + if(_tbuffer) { // remaining from last call + unsigned char * old = _tbuffer; + int new_size = size + _tbufferSize; + _tbuffer = new unsigned char[new_size]; + if(!_tbuffer) error("imuse_channel failed to allocate memory"); + memcpy(_tbuffer, old, _tbufferSize); + delete []old; + b.read(_tbuffer + _tbufferSize, size); + _tbufferSize += size; + } else { + _tbufferSize = size; + _tbuffer = new unsigned char[_tbufferSize]; + if(!_tbuffer) error("imuse_channel failed to allocate memory"); + b.read(_tbuffer, size); + } + } + return processBuffer(); +} + +bool ImuseChannel::handleFormat(Chunck & src) { + if(src.getSize() != 20) error("invalid size for FRMT chunck"); + unsigned imuse_start = src.getDword(); + imuse_start = TO_BE_32(imuse_start); + src.seek(4); + _bitsize = src.getDword(); + _bitsize = TO_BE_32(_bitsize); + _rate = src.getDword(); + _rate = TO_BE_32(_rate); + _channels = src.getDword(); + _channels = TO_BE_32(_channels); + assert(_channels == 1 || _channels == 2); + return true; +} + +bool ImuseChannel::handleText(Chunck & src) { + return true; +} + +bool ImuseChannel::handleRegion(Chunck & src) { + if(src.getSize() != 8) error("invalid size for REGN chunck"); + return true; +} + +bool ImuseChannel::handleStop(Chunck & src) { + if(src.getSize() != 4) error("invalid size for STOP chunck"); + return true; +} + +bool ImuseChannel::handleMap(Chunck & map) { + while(!map.eof()) { + Chunck * sub = map.subBlock(); + switch(sub->getType()) { + case TYPE_FRMT: + handleFormat(*sub); + break; + case TYPE_TEXT: + handleText(*sub); + break; + case TYPE_REGN: + handleRegion(*sub); + break; + case TYPE_STOP: + handleStop(*sub); + break; + default: + error("Unknown iMUS subchunck found : %s, %d", Chunck::ChunckString(sub->getType()), sub->getSize()); + } + delete sub; + } + return true; +} + +void ImuseChannel::decode() { + int remaining_size = _sbufferSize % 3; + if(remaining_size) { + _srbufferSize -= remaining_size; + assert(_inData); + if(_tbuffer == 0) { + _tbuffer = new unsigned char[remaining_size]; + memcpy(_tbuffer, _sbuffer + _sbufferSize - remaining_size, remaining_size); + _tbufferSize = remaining_size; + _sbufferSize -= remaining_size; + } else { + warning("impossible ! : %p, %d, %d, %p(%d), %p(%d, %d)", + this, _dataSize, _inData, _tbuffer, _tbufferSize, _sbuffer, _sbufferSize, _srbufferSize); + unsigned char * old = _tbuffer; + int new_size = remaining_size + _tbufferSize; + _tbuffer = new unsigned char[new_size]; + if(!_tbuffer) error("imuse_channel failed to allocate memory"); + memcpy(_tbuffer, old, _tbufferSize); + delete []old; + memcpy(_tbuffer + _tbufferSize, _sbuffer + _sbufferSize - remaining_size, remaining_size); + _tbufferSize += remaining_size; + } + } + int loop_size = _sbufferSize / 3; + int new_size = loop_size * 2; + short * keep, * decoded; + keep = decoded = new short[new_size]; + assert(keep); + unsigned char * source = _sbuffer; + while(loop_size--) { + int v1 = *source++; + int v2 = *source++; + int v3 = *source++; + int value = (((v2 & 0x0f) << 12) | (v1 << 4)) - 0x8000; + *decoded++ = (short)value; + value = (((v2 & 0xf0) << 8) | (v3 << 4)) - 0x8000; + *decoded++ = (short)value; + } + delete []_sbuffer; + _sbuffer = (unsigned char*)keep; + _sbufferSize = new_size * sizeof(short); +} + +bool ImuseChannel::handleSubTags(int & offset) { + int available_size = _tbufferSize - offset; + if(available_size >= 8) { + Chunck::type type = READ_BE_UINT32(_tbuffer + offset); + unsigned int size = READ_BE_UINT32(_tbuffer + offset + 4); + switch(type) { + case TYPE_MAP_: + _inData = false; + if(available_size >= (size + 8)) { + ContChunck c((char*)_tbuffer + offset); + handleMap(c); + } + break; + case TYPE_DATA: // Sound data !!! + _inData = true; + _dataSize = size; + offset += 8; + { + int reqsize = 1; + if(_channels == 2) reqsize *= 2; + if(_bitsize == 16) reqsize *= 2; + else if(_bitsize == 12) { + if(reqsize > 1) + reqsize = reqsize * 3 / 2; + else reqsize = 3; + } + if((size % reqsize) != 0) { + warning("Invalid iMUS sound data size : (%d %% %d) != 0, correcting...", size, reqsize); + size += 3 - (size % reqsize); + } + } + return false; + default: + error("unknown chunck in iMUS track : %s ", Chunck::ChunckString(type)); + } + offset += size + 8; + return true; + } + return false; +} + +bool ImuseChannel::processBuffer() { + // see comments in saud_channel::processBuffer for an explanation + assert(_tbuffer != 0); + assert(_tbufferSize != 0); + assert(_sbuffer == 0); + assert(_sbufferSize == 0); + + if(_inData) { + if(_dataSize < _tbufferSize) { + int offset= _dataSize; + while(handleSubTags(offset)); + _sbufferSize = _dataSize; + _sbuffer = _tbuffer; + if(offset < _tbufferSize) { // there is still some unprocessed data + int new_size = _tbufferSize - offset; + _tbuffer = new unsigned char[new_size]; + if(!_tbuffer) error("imuse_channel failed to allocate memory"); + memcpy(_tbuffer, _sbuffer + offset, new_size); + _tbufferSize = new_size; + } else { + _tbuffer = 0; + _tbufferSize = 0; + } + if(_sbufferSize == 0) { + // this never happened yet, but who knows + delete []_sbuffer; + _sbuffer = 0; + } + } else { + // easy, swap the buffer + _sbufferSize = _tbufferSize; + _sbuffer = _tbuffer; + _tbufferSize = 0; + _tbuffer = 0; + } + } else { + int offset = 0; + while(handleSubTags(offset)); + if(_inData) { + //~ unsigned char * old = _tbuffer; + _sbufferSize = _tbufferSize - offset; + assert(_sbufferSize); + _sbuffer = new unsigned char[_sbufferSize]; + if(!_sbuffer) error("imuse_channel failed to allocate memory"); + memcpy(_sbuffer, _tbuffer + offset, _sbufferSize); + delete []_tbuffer; + _tbuffer = 0; + _tbufferSize = 0; + } else { + if(offset) { // maybe I should assert() this to avoid a lock... + unsigned char * old = _tbuffer; + int new_size = _tbufferSize - offset; + _tbuffer = new unsigned char[new_size]; + if(!_tbuffer) error("imuse_channel failed to allocate memory"); + memcpy(_tbuffer, old + offset, new_size); + _tbufferSize = new_size; + delete []old; + } + } + } + _srbufferSize = _sbufferSize; + if(_sbuffer && _bitsize == 12) decode(); + return true; +} + +int ImuseChannel::availableSoundData(void) const { + int ret = _sbufferSize; + if(_channels == 2) ret /= 2; + if(_bitsize > 8) ret /= 2; + return ret; +} + +void ImuseChannel::getSoundData(short * snd, int size) { + if(_dataSize <= 0 || _bitsize <= 8) error("invalid call to imuse_channel::read_sound_data()"); + if(_channels == 2) size *= 2; + for(int i = 0; i < size; i++) + snd[i] = READ_BE_UINT16(_sbuffer + 2 * i); + delete []_sbuffer; + assert(_sbufferSize == 2 * size); + _sbuffer = 0; + _sbufferSize = 0; + _dataSize -= _srbufferSize; +} + +void ImuseChannel::getSoundData(char * snd, int size) { + if(_dataSize <= 0 || _bitsize > 8) error("invalid call to imuse_channel::read_sound_data()"); + if(_channels == 2) size *= 2; + for(int i = 0; i < size; i++) + snd[i] = _sbuffer[i]; + delete []_sbuffer; + _sbuffer = 0; + _sbufferSize = 0; + _dataSize -= _srbufferSize; +} diff --git a/scumm/smush/mixer.h b/scumm/smush/mixer.h new file mode 100644 index 00000000000..30858b6c291 --- /dev/null +++ b/scumm/smush/mixer.h @@ -0,0 +1,58 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __MIXER_H_ +#define __MIXER_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_MIXER +# define DEBUG_MIXER +# endif +#else +# ifdef DEBUG_MIXER +# error DEBUG_MIXER defined without DEBUG +# endif +#endif + +class _Channel; + +class SoundRenderer; + +/*! @brief The class for the player's sound mixer + + This class is used for sound mixing. + It contains a list of current track and request them to mix. + It then sends the mixed sound samples to the sound renderer. + +*/ +class Mixer { +public: + virtual ~Mixer() {}; + virtual bool init() = 0; + virtual _Channel * findChannel(int track) = 0; + virtual bool addChannel(_Channel * c) = 0; + virtual bool handleFrame() = 0; + virtual bool stop() = 0; +}; + +#endif diff --git a/scumm/smush/palette.cpp b/scumm/smush/palette.cpp new file mode 100644 index 00000000000..033c6b25636 --- /dev/null +++ b/scumm/smush/palette.cpp @@ -0,0 +1,56 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "palette.h" +#include "assert.h" + +Palette::Palette() { +} + +Palette::Palette(unsigned char * ptr) { + for(int i = 0; i < 256; i++) { + _colors[i] = Color(ptr[3 * i + 0], ptr[3 * i + 1], ptr[3 * i + 2]); + } +} + +Palette::Palette(const Palette & p) { + for(int i = 0; i < 256; i++) { + _colors[i] = p._colors[i]; + } +} + +const Color & Palette::operator[](int a) const { + assert(a >= 0 && a < 256); + return _colors[a]; +} + +Color & Palette::operator[](int a) { + assert(a >= 0 && a < 256); + return _colors[a]; +} + +Palette & Palette::operator=(const Palette & p) { + for(int i = 0; i < 256; i++) { + _colors[i] = p._colors[i]; + } + return *this; +} diff --git a/scumm/smush/palette.h b/scumm/smush/palette.h new file mode 100644 index 00000000000..4cc84912197 --- /dev/null +++ b/scumm/smush/palette.h @@ -0,0 +1,45 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __PALETTE_H_ +#define __PALETTE_H_ + +#include "config.h" + +#include "color.h" + +/*! @brief simple class for handling a palette. + + This small class is an helper for palettes. +*/ +class Palette { +private: + Color _colors[256]; +public: + Palette(); + Palette(unsigned char *); + Palette(const Palette &); + const Color & operator[](int) const; + Color & operator[](int); + Palette & operator=(const Palette &); +}; + +#endif diff --git a/scumm/smush/player.cpp b/scumm/smush/player.cpp new file mode 100644 index 00000000000..5362f5be9a8 --- /dev/null +++ b/scumm/smush/player.cpp @@ -0,0 +1,760 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "player.h" + +#include "renderer.h" +#include "channel.h" +#include "chunck_type.h" +#include "rect.h" +#include "blitter.h" + +#include +#include // for atoi +#include // for FILE, fopen, fclose, fread, fseek, ftell +#include // for strchr, strrchr +#include // for isdigit + +#ifndef max +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +const int WAIT = 100; + +/*! @brief parser and map of string resources + + This class implements a parser for the string resource format of SMUSH animations. + It then allows the player to get the string corresponding to a particular identifier. + + @bug some of The Dig strings are not completely parsed (in titles) +*/ + +const int MAX_STRINGS = 200; + +class StringResource { +private: + struct { + int id; + char * string; + } _strings[MAX_STRINGS]; + int _nbStrings; + int _lastId; + char * _lastString; +public: + StringResource() : _nbStrings(0), _lastId(-1) {}; + ~StringResource() { + for(int i = 0; i < _nbStrings; i++) { + delete []_strings[i].string; + } + } + /*! @brief parse the given buffer + + @param buffer the buffer that contain the resource (in lucasart format) + @param length the length of the buffer + + @return \c true if the parsing went fine, \c false otherwise + */ + bool init(char * buffer, int length) { + debug(9, "parsing string resources..."); + char * def_start = strchr(buffer, '#'); + while(def_start != NULL) { + char * def_end = strchr(def_start, '\n'); + assert(def_end != NULL); // def_end is just before the start of the string [def_start,def_end] correspond to the definition text + char * id_end = def_end; + while(id_end >= def_start && !isdigit(*(id_end-1))) id_end--; + assert(id_end > def_start); + char * id_start = id_end; + while(isdigit(*(id_start - 1))) id_start--; + // [id_start-id_end] is the id number + char idstring[32]; + memcpy(idstring, id_start, id_end - id_start); + idstring[id_end - id_start] = 0; + int id = atoi(idstring); + //~ assert(id != LONG_MIN && id != 0 && id != LONG_MAX); + char * data_start = def_end; + while(*data_start == '\n' || *data_start == '\r') data_start++; + char * data_end = data_start; + while(1) { + if(data_end[-2] == '\r' && data_end[1] == '\n' && data_end[-1] == '\n' && data_end[0] == '\r') + break; + data_end++; + if(data_end >= buffer + length) { + data_end = buffer + length; + break; + } + } + data_end -= 2; + assert(data_end > data_start); + char * value = new char[data_end - data_start + 1]; + assert(value); + memcpy(value, data_start, data_end - data_start); + value[data_end - data_start] = 0; +#ifdef DEBUG + debug(9, "Inserting (%s)%d == \"%s\"", idstring, id, value); +#endif + _strings[_nbStrings].id = id; + _strings[_nbStrings].string = value; + _nbStrings ++; + def_start = strchr(data_end + 2, '#'); + } + return true; + } + /*! @brief extract a string + + @param id the resource identifier + + @return the corresponding string. + */ + const char * get(int id) { + if(id == _lastId) return _lastString; + for(int i = 0; i < _nbStrings; i++) + { + if(_strings[i].id == id) { + _lastId = id; + _lastString = _strings[i].string; + return _strings[i].string; + } + } + warning("invalid string id : %d", id); + _lastId = -1; + _lastString = "unknown string"; + return _lastString; + } +}; + +void SmushPlayer::show(const char * p) { + if(strcmp(p, "subtitles") == 0) + _subtitles = true; + else if(strcmp(p, "bgmusic") == 0) + _bgmusic = true; + else if(strcmp(p, "voices") == 0) + _voices = true; + else { + int id = atoi(p); + if(id < 0 || id > 36) error("invalid parameter to show"); + _skips[id] = true; + } +} + +void SmushPlayer::hide(const char * p) { + if(strcmp(p, "subtitles") == 0) + _subtitles = false; + else if(strcmp(p, "bgmusic") == 0) + _bgmusic = false; + else if(strcmp(p, "voices") == 0) + _voices = false; + else { + int id = atoi(p); + if(id < 0 || id > 36) error("invalid parameter to hide"); + _skips[id] = false; + } +} + +SmushPlayer::SmushPlayer(Renderer * renderer, bool wait, bool sound) : + _version(-1), + _secondaryVersion(0), + _soundFrequency(0), + _nbframes(0), + _mixer(0), + _renderer(renderer), + _strings(0), + _frameSize(-1, -1), + _frame(0), + _outputSound(sound), + _wait(wait), + _alreadyInit(false), + _codec37Called(false), + _skipNext(false), + _subtitles(true), + _bgmusic(true), + _voices(true) { + _fr[0] = _fr[1] = _fr[2] = _fr[3] = 0; + assert(_renderer != 0); +} + +SmushPlayer::~SmushPlayer() { + clean(); + //~ if(_mixer) delete _mixer; +} + +void SmushPlayer::updatePalette(void) { + _renderer->setPalette(_pal); +} + +void SmushPlayer::clean() { + if(_strings) + delete _strings; + if(_fr[0]) delete _fr[0]; + if(_fr[1]) delete _fr[1]; + if(_fr[2]) delete _fr[2]; + if(_fr[3]) delete _fr[3]; +} + +void SmushPlayer::checkBlock(const Chunck & b, Chunck::type type_expected, unsigned int min_size) { + if(type_expected != b.getType()) { + error("chunck type is different from expected : %d != %d", b.getType(), type_expected); + } + if(min_size > b.getSize()) { + error( "chunck size is inferior than minimum required size : %d < %d", b.getSize(), min_size); + } +} + +void SmushPlayer::handleSoundBuffer(int track_id, int index, int max_frames, int flags, int vol, int bal, Chunck & b, int size) { + debug(6, "smush_player::handleSoundBuffer(%d)", track_id); + if(!_voices && (flags & 128) == 128) return; + if(!_bgmusic && (flags & 64) == 64) return; + _Channel * c = _mixer->findChannel(track_id); + if(c == 0) { + c = new SaudChannel(track_id, _soundFrequency); + _mixer->addChannel(c); + } + if(index == 0) + c->setParameters(max_frames, flags, vol, bal); + else + c->checkParameters(index, max_frames, flags, vol, bal); + c->appendData(b, size); +} + +void SmushPlayer::handleSoundFrame(Chunck & b) { + checkBlock(b, TYPE_PSAD); + debug(6, "SmushPlayer::handleSoundFrame()"); + if(!_outputSound) return; + int track_id = b.getWord(); + int index = b.getWord(); + int max_frames = b.getWord(); + int flags = b.getWord(); + int vol = b.getByte(); + int bal = b.getChar(); +#ifdef DEBUG + if(index == 0) { + debug(5, "track_id == %d, max_frames == %d, %d, %d, %d", track_id, max_frames, flags, vol, bal); + } +#endif + int size = b.getSize() - 10; + handleSoundBuffer(track_id, index, max_frames, flags, vol, bal, b, size); +} + +void SmushPlayer::handleSkip(Chunck & b) { + checkBlock(b, TYPE_SKIP, 4); + int code = b.getDword(); + debug(6, "SmushPlayer::handleSkip(%d)", code); + if(code >= 0 && code < 37) + _skipNext =_skips[code]; + else + _skipNext =true; +} + +void SmushPlayer::handleStore(Chunck & b) { + checkBlock(b, TYPE_STOR, 4); + debug(6, "SmushPlayer::handleStore()"); +} + +void SmushPlayer::handleFetch(Chunck & b) { + checkBlock(b, TYPE_FTCH, 6); + debug(6, "SmushPlayer::handleFetch()"); +} + +void SmushPlayer::handleImuseBuffer(int track_id, int index, int nbframes, int size, int unk1, int unk2, Chunck & b, int bsize) { + _Channel * c = _mixer->findChannel(track_id); + if(c == 0) { + c = new ImuseChannel(track_id, _soundFrequency); + _mixer->addChannel(c); + } + if(index == 0) + c->setParameters(nbframes, size, unk1, unk2); + else + c->checkParameters(index, nbframes, size, unk1, unk2); + c->appendData(b, bsize); +} + +void SmushPlayer::handleImuseAction8(Chunck & b, int flags, int unknown, int track_id) { + assert(flags == 46 && unknown == 0); + int unknown2 = b.getWord(); + track_id |= unknown2 << 16; + int index = b.getWord(); + int nbframes = b.getWord(); + int size = b.getDword(); + int bsize = b.getSize() - 18; + handleImuseBuffer(track_id, index, nbframes, size, unknown, unknown2, b, bsize); +} + +void SmushPlayer::handleImuseAction(Chunck & b) { + checkBlock(b, TYPE_IACT, 8); + debug(6, "SmushPlayer::handleImuseAction()"); + if(!_outputSound) return; + int code = b.getWord(); + int flags = b.getWord(); + int unknown = b.getShort(); + int track_id = b.getWord(); +#ifdef DEBUG + debug(5, "handleImuseAction(%d, %d, %d, %d)", code, flags, unknown, track_id); +#endif + switch(code) { + case 8: + handleImuseAction8(b, flags, unknown, track_id); + break; +#ifdef DEBUG + default: { + debug(9, "%5.5d %d %8.8d %4.4d", track_id, flags, unknown); + } +#endif + } +} + +void SmushPlayer::handleTextResource(Chunck & b) { + checkBlock(b, TYPE_TRES, 18); + int pos_x = b.getShort(); + int pos_y = b.getShort(); + int flags = b.getShort(); + int left = b.getShort(); + int top = b.getShort(); + int width = b.getShort(); + int height = b.getShort(); + int unk2 = b.getWord(); + int string_id = b.getWord(); + debug(6, "SmushPlayer::handleTextResource(%d)", string_id); + if(!_strings) return; + + // if subtitles disabled and bit 3 is set, then do not draw + if((!_subtitles) && ((flags & 8) == 8)) return; + const char * str = _strings->get(string_id); + + FontRenderer * fr = _fr[0]; + int color = 15; + while(*str == '/') str++; // For Full Throttle text resources + while(str[0] == '^') { + switch(str[1]) { + case 'f': + { +#if 0 + // This cause trouble if the next character is a digit. + int id = atoi(str+2); +#else + // assume ASCII like character set... + int id = str[3] - '0'; +#endif + str += 4; + fr = _fr[id]; + } break; + case 'c': + { + //~ int id = atoi(str+2); + color = str[4] - '0' + 10 *(str[3] - '0'); + str += 5; + } break; + default: + error("invalid escape code in text string"); + } + } + assert(fr != 0); + fr->setColor(color); + if(!_curBuffer) { _curBuffer = _renderer->lockFrame(_frame); } + if(flags == 0 || flags == 4) { + fr->drawStringAbsolute(str, _curBuffer, _frameSize, pos_x, pos_y); + } else { + fr->drawStringCentered(str, _curBuffer, _frameSize, max(pos_y, top), left, width, pos_x); + } +} + +void SmushPlayer::readPalette(Palette & out, Chunck & in) { + unsigned char buffer[768]; + in.read(buffer, 768); + out = Palette(buffer); +} + +void SmushPlayer::handleDeltaPalette(Chunck & b) { + checkBlock(b, TYPE_XPAL); + debug(6, "SmushPlayer::handleDeltaPalette()"); + if(b.getSize() == 768 * 3 + 4) { + int unk1, num; + unk1 = b.getWord(); + num = b.getWord(); + for(int i = 0; i < 768; i++) { + _deltaPal[i] = b.getWord(); + } + readPalette(_pal, b); + updatePalette(); + } else if(b.getSize() == 6) { + int unk1, num, unk2; + unk1 = b.getWord(); + num = b.getWord(); + unk2 = b.getWord(); + for(int i = 0; i < 256; i++) { + _pal[i].delta(_deltaPal + 3 * i); + } + updatePalette(); + } else { + error("wrong size for DeltaPalette"); + } +} + +void SmushPlayer::handleNewPalette(Chunck & b) { + checkBlock(b, TYPE_NPAL, 768); + debug(6, "SmushPlayer::handleNewPalette()"); + readPalette(_pal, b); + updatePalette(); +} + +void SmushPlayer::decodeCodec(Chunck & b, const Rect & r, Decoder & codec) { + assert(_curBuffer); + Blitter blit(_curBuffer, _frameSize, r); + codec.decode(blit, b); +} + +void SmushPlayer::initSize(const Rect & r, bool always, bool transparent) { + if(_codec37Called) _alreadyInit = true; + + if(!_alreadyInit || _frameSize.getX() < r.right() || _frameSize.getY() < r.bottom() || always) { + if(_curBuffer) { + _renderer->unlockFrame(); + _curBuffer = 0; + } + _frameSize = r.bottomRight(); + _renderer->initFrame(_frameSize); + } + + if(_curBuffer) { + _renderer->unlockFrame(); + _curBuffer = 0; + } + + _curBuffer = _renderer->lockFrame(_frame); + if(!_alreadyInit && transparent) { + memset(_curBuffer, 0, _frameSize.getX()*_frameSize.getY()); + } + + _codec1.initSize(_frameSize, r); + _codec37.initSize(_frameSize, r); + _codec44.initSize(_frameSize, r); + _codecd.initSize(_frameSize, r); + _alreadyInit = true; +} + +void SmushPlayer::handleFrameObject(Chunck & b) { + checkBlock(b, TYPE_FOBJ, 14); + if(_skipNext) { + _skipNext = false; + return; + } + int codec = b.getWord(); + debug(6, "SmushPlayer::handleFrameObject(%d)", codec); + unsigned short left = b.getWord(); + unsigned short top = b.getWord(); + unsigned short width = b.getWord(); + unsigned short height = b.getWord(); + Rect r(left, top, left + width, top + height); + unsigned short data[2]; + data[1] = b.getWord(); + data[0] = b.getWord(); +#ifdef DEBUG + debug(5, "Frame pos : %d, %d", left, top); + debug(5, "Frame size : %dx%d", width, height); + debug(5, "Codec : %d", codec); +#endif + switch (codec) { + case 3: + case 1: + initSize(r, false, true); + decodeCodec(b, r, _codec1); + break; + case 37: + assert(left == 0 && top == 0); + initSize(r, true, false); + decodeCodec(b, r, _codec37); + _codec37Called = true; + break; + case 47: + initSize(r, false, true); + decodeCodec(b, r, _codecd); + break; + case 21: + case 44: + initSize(r, true, true); + decodeCodec(b, r, _codec44); + break; + default: + error("Invalid codec for frame object : %d", (int)codec); + } +} + +void SmushPlayer::handleFrame(Chunck & b) { + checkBlock(b, TYPE_FRME); + debug(6, "SmushPlayer::handleFrame(%d)", _frame); + _alreadyInit = false; + _skipNext = false; + + while(!b.eof()) { + Chunck * sub = b.subBlock(); + if(sub->getSize() & 1) b.seek(1); + switch(sub->getType()) { + case TYPE_NPAL: + handleNewPalette(*sub); + break; + case TYPE_FOBJ: + handleFrameObject(*sub); + break; + case TYPE_PSAD: + handleSoundFrame(*sub); + break; + case TYPE_TRES: + handleTextResource(*sub); + break; + case TYPE_XPAL: + handleDeltaPalette(*sub); + break; + case TYPE_IACT: + handleImuseAction(*sub); + break; + case TYPE_STOR: + handleStore(*sub); + break; + case TYPE_FTCH: + handleFetch(*sub); + break; + case TYPE_SKIP: + handleSkip(*sub); + break; + default: + error("Unknown frame subchunck found : %s, %d", Chunck::ChunckString(sub->getType()), sub->getSize()); + } + delete sub; + } + if(_curBuffer) { + _renderer->unlockFrame(); + _curBuffer = 0; + } + if(_outputSound) + _mixer->handleFrame(); +#ifdef DEBUG + debug(5, "===================END OF FRAME========================"); +#endif + _renderer->flipFrame(); + if(_wait) + _renderer->wait(WAIT); + _frame++; +} + +void SmushPlayer::handleAnimHeader(Chunck & b) { + checkBlock(b, TYPE_AHDR, 774); + debug(6, "SmushPlayer::handleAnimHeader()"); + _version = b.getWord(); + _nbframes = b.getWord(); + int unknown = b.getWord(); +#ifdef DEBUG + debug(5, "SMUSH HEADER : version == %d, nbframes == %d, unknown == %d", _version, _nbframes, unknown); +#else + unknown = unknown; +#endif + _renderer->startDecode(_fname, _version, _nbframes); + readPalette(_pal, b); + updatePalette(); + if(_version == 1) { + _soundFrequency = 22050; + } + if(_version == 2) { + _secondaryVersion = b.getDword(); + int unknown2 = b.getDword(); + _soundFrequency = b.getDword(); +#ifdef DEBUG + debug(5, "SMUSH HEADER : secondary version == %d, unknown2 == %d, sound frequency == %d", _secondaryVersion, unknown2, _soundFrequency); + int i = 0, c; + while(!b.eof()) { + c = b.getByte(); + if(c) debug(9, "SMUSH HEADER : remaining bytes : %d == %d", i, c); + i++; + } +#else + unknown2 = unknown2; +#endif + if(_secondaryVersion != 10 && _secondaryVersion != 0 && _secondaryVersion != 12 && _secondaryVersion != 15 && _secondaryVersion != 14) + error("Wrong secondary version number for SMUSH animation"); + if(_soundFrequency != 0 && _soundFrequency != 11025 && _soundFrequency != 22050) + error("Wrong _sound_frequency number for SMUSH animation"); + }else if(_version > 2) { + error("Wrong primary version number for SMUSH animation"); + } + if(_outputSound && _soundFrequency) { + if(_soundFrequency != 22050) _soundFrequency = 22050; + _mixer = _renderer->getMixer(); + if(_mixer) { + _mixer->init(); + } else { + _outputSound = false; + } + } +} + +static StringResource * getStrings(const char * file, bool is_encoded) { + debug(7, "trying to read text ressources from %s", file); + FILE * is; + is = fopen(file, "rb"); + if(is == NULL) return 0; + fseek(is, 0, SEEK_END); + int length = ftell(is); + fseek(is, 0, SEEK_SET); + char * filebuffer = new char [length + 1]; + assert(filebuffer); + fread (filebuffer, length, 1, is); + filebuffer[length] = 0; + fclose(is); + if(is_encoded) { + static const int ETRS_HEADER_LENGTH = 16; + assert(length > ETRS_HEADER_LENGTH); + Chunck::type type = READ_BE_UINT32(filebuffer); + if(type != TYPE_ETRS) error("invalid type for file"); // mem leak !!! + char * old = filebuffer; + filebuffer = new char[length - ETRS_HEADER_LENGTH]; + for(int i = ETRS_HEADER_LENGTH; i < length; i++) + filebuffer[i - ETRS_HEADER_LENGTH] = old[i] ^ 0xCC; + delete []old; + length -= ETRS_HEADER_LENGTH; + } + StringResource * sr = new StringResource; + assert(sr); + sr->init(filebuffer, length); + delete []filebuffer; + return sr; +} + +bool SmushPlayer::readString(const char * file, bool & ft) { + const char * i = strrchr(file, '.'); + if(i == NULL) error("invalid filename : %s", file); + char fname[260]; + memcpy(fname, file, i - file); + strcpy(fname + (i - file), ".trs"); + if((_strings = getStrings(fname, false)) != 0) { + ft = true; + return true; + } + i = strrchr(file, '\\'); + if(i == NULL) i = strrchr(file, '/'); + else { + char * j = strrchr(file, '/'); + if(j > i) i = j; + } + if(i == NULL) error("invalid filename : %s", file); + + memcpy(fname, file, i - file + 1); + strcpy(fname + (i - file + 1), "digtxt.trs"); + if((_strings = getStrings(fname, true)) != 0) { + ft = false; + return true; + } + return false; +} + +static FontRenderer * loadFont(const char * file, bool original = false) { +#ifdef DEBUG + debug(5, "loading font from \"%s\"", file); +#endif + FontRenderer * fr = new FontRenderer(original); + SmushPlayer p(fr, false, false); + p.play(file); + return fr; +} + +bool SmushPlayer::play(const char * file) { +#ifdef DEBUG + debug(5, "start of animation : %s", file); +#endif + char * i = strrchr(file, '\\'); + if(i == NULL) + { + i = strrchr(file, '/'); + } else { + char * j = strrchr(i, '/'); + if(j != NULL) + i = j; + } + char directory[260]; + if(i != NULL) { + strcpy(directory, file); + directory[i-file] = 0; + //! @todo remove this... + _fname = strdup(i); + } else { + directory[0] = 0; + _fname = strdup(file); + } + clean(); + + if(_wait) { + bool isFullthrottle; + if(!readString(file, isFullthrottle)) + warning("unable to read text information for \"%s\"", file); + if(_strings) { + if(isFullthrottle) { + if(strcmp(directory, "") == 0) { + strcpy(directory, "../data/"); + } else { + char * i = strrchr(directory, '\\'); + char * j = strrchr(directory, '/'); + if(j > i) i = j; + if(i == NULL) { + strcpy(directory, "data/"); + } else { + *i = 0; + strcat(directory, "/data/"); + } + } + char file[260]; + strcpy(file, directory); strcat(file, "scummfnt.nut"); + _fr[0] = loadFont(file, true); + strcpy(file, directory); strcat(file, "titlfnt.nut"); + _fr[2] = loadFont(file, true); + } else { + for(int i = 0; i < 4; i++) { + char file[260]; + sprintf(file, "%s/font%d.nut",directory, i); + _fr[i] = loadFont(file, i != 0); + } + } + } + } + FileChunck base = FileChunck(file); + + checkBlock(base, TYPE_ANIM); + + while(!base.eof()) { + Chunck * sub = base.subBlock(); + switch(sub->getType()) { + case TYPE_AHDR: + handleAnimHeader(*sub); + break; + case TYPE_FRME: + handleFrame(*sub); + break; + default: + error("Unknown chunck found : %d, %d", sub->getType(), sub->getSize()); + } + delete sub; + if(_renderer->prematureClose()) + break; + } +#ifdef DEBUG + debug(5, "end of animation"); +#endif + if(_outputSound) { + _mixer->stop(); + } + return true; +} diff --git a/scumm/smush/player.h b/scumm/smush/player.h new file mode 100644 index 00000000000..ceb58eaee2a --- /dev/null +++ b/scumm/smush/player.h @@ -0,0 +1,104 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __PLAYER_H_ +#define __PLAYER_H_ + +#include "config.h" + +#include "rect.h" +#include "mixer.h" +#include "chunck.h" +#include "palette.h" +#include "codec1.h" +#include "codec37.h" +#include "codec44.h" +#include "codec47.h" +#include "frenderer.h" + +class Renderer; + +class StringResource; + +/*! @brief the SMUSH player class + + This class is the player itself. +*/ +class SmushPlayer { +private: + char * _fname; //!< the name of the animation file being played + int _version; //!< the version of the animation file being played + int _secondaryVersion; //!< the secondary version number of the animation file being played + int _soundFrequency; //!< the sound frequency of the animation file being played + int _nbframes; //!< the number of frames in the animation file + Mixer * _mixer; //!< the sound mixer + Palette _pal; //!< the current palette + short _deltaPal[768]; //!< the delta palette information set by an xpal + Renderer * _renderer; //!< pointer to the ::renderer + StringResource * _strings; //!< pointer to the string resources associated with the animation + FontRenderer * _fr[4]; //!< pointers to the fonts for the animation + Codec1Decoder _codec1; //!< the ::decoder for codec 1 and 3 + Codec37Decoder _codec37; //!< the ::decoder for codec 37 + Codec44Decoder _codec44; //!< the ::decoder for codec 21 and 44 + DumpDecoder _codecd; //!< the ::decoder for codec 21 and 44 + Point _frameSize; //!< the current frame size of the animation + int _frame; //!< the current frame number of the animation + bool _outputSound; //!< should we handle sound ? + bool _wait; //!< should we synchronise the player ? + bool _alreadyInit; //!< has the player already been initialized for the current frame + bool _codec37Called; //!< has the codec 37 already been called once for this animation + bool _skipNext; //!< should the player skip the next frame object ? + bool _subtitles; //!< should the player handle subtitles ? + bool _bgmusic; //!< should the player output the background music ? + bool _voices; //!< should the player output the voice ? + bool _skips[37]; //!< mapping of frame object identifier to show or hide + char * _curBuffer; //!< pointer to the current frame +public: + SmushPlayer(Renderer *, bool wait = true, bool output_sound = true); + virtual ~SmushPlayer(); + bool play(const char *); + void updatePalette(void); + void show(const char *); + void hide(const char *); +protected: + bool readString(const char * file, bool &); + void clean(); + void checkBlock(const Chunck &, Chunck::type, unsigned int = 0); + void handleAnimHeader(Chunck &); + void handleFrame(Chunck &); + void handleNewPalette(Chunck &); + void handleFrameObject(Chunck &); + void handleSoundBuffer(int, int, int, int, int, int, Chunck &, int); + void handleImuseBuffer(int, int, int, int, int, int, Chunck &, int); + void handleSoundFrame(Chunck &); + void handleSkip(Chunck &); + void handleStore(Chunck &); + void handleFetch(Chunck &); + void handleImuseAction8(Chunck &, int flags, int unknown, int track_id); + void handleImuseAction(Chunck &); + void handleTextResource(Chunck &); + void handleDeltaPalette(Chunck &); + void decodeCodec(Chunck &, const Rect &, Decoder &); + void readPalette(Palette &, Chunck &); + void initSize(const Rect &, bool, bool); +}; + +#endif diff --git a/scumm/smush/rect.cpp b/scumm/smush/rect.cpp new file mode 100644 index 00000000000..deb1d5b35f2 --- /dev/null +++ b/scumm/smush/rect.cpp @@ -0,0 +1,62 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "rect.h" + +Rect::Rect() : _topLeft(0, 0), _bottomRight(0,0) { +} + +Rect::Rect(int x, int y) : _topLeft(0, 0), _bottomRight(x, y) { + check(); +} + +Rect::Rect(int x1, int y1, int x2, int y2) : _topLeft(x1, y1), _bottomRight(x2, y2) { + check(); +} + +Rect::Rect(const Rect & r) : _topLeft(r._topLeft), _bottomRight(r._bottomRight) { +} + +Rect & Rect::operator=(const Rect & r) { + _topLeft = r._topLeft; + _bottomRight = r._bottomRight; + return *this; +} + +bool Rect::operator==(const Rect & r) const { + return _topLeft == r._topLeft && _bottomRight == r._bottomRight; +} + +void Rect::check() { + if ((_topLeft.getX() < 0) || (_bottomRight.getX() < _topLeft.getX()) || (_topLeft.getY() < 0) || (_bottomRight.getY() < _topLeft.getY())) { + error("Invalid rect"); + } +} + +bool Rect::isInside(int x, int y) const { + return _topLeft.getX() >= x && _bottomRight.getX() < x && _topLeft.getY() >= y && _bottomRight.getY() < y; +} + +bool Rect::isInside(const Point & p) const { + return (left() <= p.getX()) && (right() > p.getX()) && (top() <= p.getY()) && (bottom() > p.getY()); +} + diff --git a/scumm/smush/rect.h b/scumm/smush/rect.h new file mode 100644 index 00000000000..c7483f54ef9 --- /dev/null +++ b/scumm/smush/rect.h @@ -0,0 +1,101 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __RECT_H_ +#define __RECT_H_ + +#include "config.h" + +/*! @brief simple class for handling both 2D position and size + + This small class is an helper for position and size values. +*/ +class Point { +private: + int _x; //!< The horizontal part of the point + int _y; //!< The vertical part of the point +public: + Point() : _x(0), _y(0) {}; + Point(const Point & p) : _x(p.getX()), _y(p.getY()) {}; + explicit Point(int x, int y) : _x(x), _y(y) {}; + Point & operator=(const Point & p) { _x = p.getX(); _y = p.getY(); return *this; }; + bool operator==(const Point & p) const { return _x == p.getX() && _y == p.getY(); }; + const int & getX() const { return _x; }; + const int & getY() const { return _y; }; + int & getX() { return _x; }; + int & getY() { return _y; }; + Point operator+(const Point & p) const { return Point(_x + p.getX(), _y+p.getY()); }; + Point operator-(const Point & p) const { return Point(_x - p.getX(), _y-p.getY()); }; + Point & operator+=(const Point & p) { _x += p.getX(); _y += p.getY(); return *this; }; + Point & operator-=(const Point & p) { _x -= p.getX(); _y -= p.getY(); return *this; }; + bool isOrigin() const { return *this == Point(0, 0); }; + void set(int x, int y) { _x = x; _y = y; } +}; + +/*! @brief simple class for handling a rectangular zone. + + This small class is an helper for rectangles. + It is mostly used by the blitter class. +*/ +class Rect { +private: + Point _topLeft; //!< The point at the top left of the rectangle + Point _bottomRight; //!< The point at the bottom right of the rectangle +protected: + void check(); +public: + Rect(); + Rect(int x, int y); + explicit Rect(const Point & size); + Rect(int x1, int y1, int x2, int y2); + Rect(const Point & topleft, const Point & bottomright); + Rect(const Rect & r); + Rect & operator=(const Rect & r); + bool operator==(const Rect & r) const; + Point size() const { return (_bottomRight - _topLeft); }; + int width() const { return size().getX(); } + int height() const { return size().getY(); } + int left() const { return _topLeft.getX(); } + int right() const { return _bottomRight.getX(); } + int top() const { return _topLeft.getY(); } + int bottom() const { return _bottomRight.getY(); } + const Point & topLeft() const { return _topLeft; } + const Point & bottomRight() const { return _bottomRight; } + + /*! @brief check if given position is inside the rectangle + + @param x the horizontal position to check + @param y the vertical position to check + + @return true if the given position is inside the rectangle, false otherwise + */ + bool isInside(int x, int y) const; + /*! @brief check if given point is inside the rectangle + + @param p the point to check + + @return true if the given point is inside the rectangle, false otherwise + */ + bool isInside(const Point & p) const; + bool clip(Rect & r) const; +}; + +#endif diff --git a/scumm/smush/renderer.h b/scumm/smush/renderer.h new file mode 100644 index 00000000000..dde44a3afe8 --- /dev/null +++ b/scumm/smush/renderer.h @@ -0,0 +1,123 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __RENDERER_H_ +#define __RENDERER_H_ + +#include "config.h" + +#include "rect.h" + +class Palette; +class Mixer; + +/*! @brief interface for general output (rendering) + + This is the interface for frame output. + Several implementations of these interface exist, each having a particular + application. +*/ +class Renderer { +public: + virtual ~Renderer() {}; + /*! @brief start of animation output + + This is called by the animation player when output is going to start. + + @param fname name of the animation being played. + @param version version number of the animation + @param nbframes total number of frames of the animation. + + @return true if initialisation was ok, false otherwise + */ + virtual bool startDecode(const char * fname, int version, int nbframes) = 0; + /*! @brief start of animation output + + This is called by the animation player when the frame size is changing. + + @param size new size of the frames. + + @return true if everything went fine, false otherwise + */ + virtual bool initFrame(const Point & size) = 0; + /*! @brief set a new palette + + This is called by the animation player when the palette is changing. + + @param pal new palette. + + @return true if everything went fine, false otherwise + */ + virtual bool setPalette(const Palette & pal) = 0; + /*! @brief lock a frame buffer + + This is called by the animation player when a frame is going to be decoded. + + @param frame the frame number. + + @return a pointer to the frame buffer to output data to. + */ + virtual char * lockFrame(int frame) = 0; + /*! @brief unlock a frame buffer + + This is called by the animation player when a frame has been decoded. + + @return true if everything went fine, false otherwise + */ + virtual bool unlockFrame() = 0; + /*! @brief flip a frame buffer + + This is called by the animation player when the current frame should be shown. + + @return true if everything went fine, false otherwise + */ + virtual bool flipFrame() = 0; + /*! @brief wait for some time + + This is called by the animation player when the animation should stay idle. + + @param ms number of millisecond to wait. + + @return true if everything went fine, false otherwise + */ + virtual bool wait(int ms) = 0; + /*! @brief does the renderer want a premature end of the animation ? + + This is called by the animation player after each frame. + + @return true if playing should be stopped, false otherwise. + */ + virtual bool prematureClose() = 0; + /*! @brief request for a mixer + + This is called by the animation player when sound output is required by the animation. + + @return a valid pointer to an uninitialized mixer instance, or null if none is available. + */ + virtual Mixer * getMixer() = 0; + /*! @brief debugging function : do not use + + @return true if everything went fine, false otherwise + */ + virtual bool saveCurrent() { return false; }; +}; + +#endif diff --git a/scumm/smush/saud_channel.cpp b/scumm/smush/saud_channel.cpp new file mode 100644 index 00000000000..8fd584b659f --- /dev/null +++ b/scumm/smush/saud_channel.cpp @@ -0,0 +1,274 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "channel.h" +#include "chunck.h" +#include "chunck_type.h" + +#include +#include // for memcpy.h +#ifndef min +#define min(x, y) ((x) > (y) ? (y) : (x)) +#endif + +void SaudChannel::handleStrk(Chunck & b) { + int size = b.getSize(); + if(size != 14 && size != 10) { + error("STRK has a invalid size : %d", size); + } +} + +void SaudChannel::handleSmrk(Chunck & b) { + _markReached = true; +} + +void SaudChannel::handleShdr(Chunck & b) { + int size = b.getSize(); + if(size != 4) warning("SMRK has a invalid size : %d", size); +} + +bool SaudChannel::handleSubTags(int & offset) { + int available_size = _tbufferSize - offset; + if(available_size >= 8) { + Chunck::type type = READ_BE_UINT32(_tbuffer + offset); + unsigned int size = READ_BE_UINT32(_tbuffer + offset + 4); + + switch(type) { + case TYPE_STRK: + _inData = false; + if(available_size >= (size + 8)) { + ContChunck c((char*)_tbuffer + offset); + handleStrk(c); + } + else + return false; + break; + case TYPE_SMRK: + _inData = false; + if(available_size >= (size + 8)) { + ContChunck c((char*)_tbuffer + offset); + handleSmrk(c); + } + else + return false; + break; + case TYPE_SHDR: + _inData = false; + if(available_size >= (size + 8)) { + ContChunck c((char*)_tbuffer + offset); + handleShdr(c); + } + else + return false; + break; + case TYPE_SDAT: + _inData = true; + _dataSize = size; + offset += 8; + return false; + default: + error("unknown chunck in SAUD track : %s ", Chunck::ChunckString(type)); + } + offset += size + 8; + return true; + } + return false; +} + +bool SaudChannel::processBuffer() { + // At the start of this function, we have _tbuffer[0.._tbuffersize] containing possible data... + // and _sbuffer is 0 + // At the end we have : + // if(sound data) _sbuffer[0.._sbuffer_size] contains the sound data + // the unprocessed data is kept in _tbuffer[0.._tbuffersize] (which may have changed) + // if no unprocessed data, then _tbuffer is 0 + assert(_tbuffer != 0); + assert(_tbufferSize != 0); + assert(_sbuffer == 0); + assert(_sbufferSize == 0); + + if(_inData) { + if(_dataSize < _tbufferSize) { + // I can't assume that the channel is finished after data is received... (this assumption failed in realride.san) + int offset= _dataSize; + while(handleSubTags(offset)); + _sbufferSize = _dataSize; + _sbuffer = _tbuffer; + if(offset < _tbufferSize) { // there is still some unprocessed data + int new_size = _tbufferSize - offset; + _tbuffer = new unsigned char[new_size]; + if(!_tbuffer) error("SaudChannel failed to allocate memory"); + memcpy(_tbuffer, _sbuffer + offset, new_size); + _tbufferSize = new_size; + } else { + _tbuffer = 0; + _tbufferSize = 0; + } + if(_sbufferSize == 0) { + // this never happened yet, but who knows + delete []_sbuffer; + _sbuffer = 0; + } + } else { + // easy, swap the buffer + _sbufferSize = _tbufferSize; + _sbuffer = _tbuffer; + _tbufferSize = 0; + _tbuffer = 0; + } + } else { + int offset = 0; + while(handleSubTags(offset)); + if(_inData) { + _sbufferSize = _tbufferSize - offset; + assert(_sbufferSize); + _sbuffer = new unsigned char[_sbufferSize]; + if(!_sbuffer) error("saud_channel failed to allocate memory"); + memcpy(_sbuffer, _tbuffer + offset, _sbufferSize); + delete []_tbuffer; + _tbuffer = 0; + _tbufferSize = 0; + } else { + if(offset) { // maybe I should assert() this to avoid a lock... + unsigned char * old = _tbuffer; + int new_size = _tbufferSize - offset; + _tbuffer = new unsigned char[new_size]; + if(!_tbuffer) error("SaudChannel failed to allocate memory"); + memcpy(_tbuffer, old + offset, new_size); + _tbufferSize = new_size; + delete []old; + } + } + } + return true; +} + +SaudChannel::SaudChannel(int track, int freq) : + _track(track), + _nbframes(0), + _dataSize(-1), + _tbuffer(0), + _sbuffer(0), + _frequency(freq), + _tbufferSize(0), + _sbufferSize(0), + _inData(false), + _markReached(false) + { +} + +SaudChannel::~SaudChannel() { + if(_tbuffer) delete []_tbuffer; + if(_sbuffer) { + warning("this should never happen !!!! (_sbuffer not NULL here)"); + delete []_sbuffer; + } +} + +bool SaudChannel::isTerminated() const { + return (_markReached && _dataSize == 0 && _sbuffer == 0); +} + +void SaudChannel::recalcVolumeTable() { + const int MAX_BALANCE = 100; + int volume_left, volume_right; + if(_balance < -MAX_BALANCE || _balance > MAX_BALANCE) { + error("balance is out of range ! : %d", _balance); + } + int left_multiplier = MAX_BALANCE - _balance; + int right_multiplier = MAX_BALANCE + _balance; + volume_left = _volume * left_multiplier / (MAX_BALANCE * 2); + volume_right = _volume * right_multiplier / (MAX_BALANCE * 2); + if(volume_left < 0) volume_left = 0; + if(volume_left > 128) volume_left = 128; + if(volume_right < 0) volume_right = 0; + if(volume_right > 128) volume_right = 128; + for(int i = 0; i < 256; i++) { + int value = volume_left * (signed char)i; + _voltable[0][i] = TO_BE_16(value); + value = volume_right * (signed char)i; + _voltable[1][i] = TO_BE_16(value); + } +} + +bool SaudChannel::setParameters(int nb, int flags, int volume, int balance) { + _nbframes = nb; + _flags = flags; // bit 7 == IS_VOICE, bit 6 == IS_BACKGROUND_MUSIC, other ?? + _volume = volume; + _balance = balance; + _index = 0; + recalcVolumeTable(); + return true; +} + +bool SaudChannel::checkParameters(int index, int nb, int flags, int volume, int balance) { + if(++_index != index) error("invalid index in SaudChannel::checkParameters()"); + if(_nbframes != nb) error("invalid duration in SaudChannel::checkParameters()"); + if(_flags != flags) error("invalid flags in SaudChannel::checkParameters()"); + if(_volume != volume || _balance != balance) { + _volume = volume; + _balance = balance; + recalcVolumeTable(); + } + return true; +} + +bool SaudChannel::appendData(Chunck & b, int size) { + if(_dataSize == -1) { // First call + assert(size > 8); + Chunck::type saud_type = b.getDword(); saud_type = TO_BE_32(saud_type); + unsigned int saud_size = b.getDword(); saud_size = TO_BE_32(saud_size); + if(saud_type != TYPE_SAUD) error("Invalid CHUNCK for SaudChannel : %X", saud_type); + size -= 8; + _dataSize = -2; // We don't get here again... + } + if(_tbuffer) { + unsigned char * old = _tbuffer; + _tbuffer = new unsigned char[_tbufferSize + size]; + if(!_tbuffer) error("saud_channel failed to allocate memory"); + memcpy(_tbuffer, old, _tbufferSize); + delete []old; + b.read(_tbuffer + _tbufferSize, size); + _tbufferSize += size; + } else { + _tbufferSize = size; + _tbuffer = new unsigned char[_tbufferSize]; + if(!_tbuffer) error("saud_channel failed to allocate memory"); + b.read(_tbuffer, _tbufferSize); + } + return processBuffer(); +} + +int SaudChannel::availableSoundData(void) const { + return _sbufferSize; +} + +void SaudChannel::getSoundData(short * snd, int size) { + for(int i = 0; i < size; i++) { + snd[2 * i] = _voltable[0][_sbuffer[i] ^ 0x80]; + snd[2 * i + 1] = _voltable[1][_sbuffer[i] ^ 0x80]; + } + _dataSize -= size; + delete []_sbuffer; + _sbuffer = 0; + _sbufferSize = 0; +} diff --git a/scumm/smush/scumm_renderer.cpp b/scumm/smush/scumm_renderer.cpp new file mode 100644 index 00000000000..bfce102ae58 --- /dev/null +++ b/scumm/smush/scumm_renderer.cpp @@ -0,0 +1,266 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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 +#include "scumm_renderer.h" +#include "channel.h" + +class scumm_mixer : public Mixer { +private: + SoundMixer * _mixer; //!< pointer to the SoundMixer instance + struct { + int id; + _Channel * chan; + bool first; + int mixer_index; + } _channels[SoundMixer::NUM_CHANNELS]; //!< The map of track and channels + int _nextIndex; +public: + scumm_mixer(SoundMixer *); + virtual ~scumm_mixer(); + bool init(); + _Channel * findChannel(int track); + bool addChannel(_Channel * c); + bool handleFrame(); + bool stop(); + bool update(); +}; + +scumm_mixer::scumm_mixer(SoundMixer * m) : _mixer(m), _nextIndex(0) { + for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) { + _channels[i].id = -1; + _channels[i].chan = 0; + _channels[i].first = true; + } +} + +scumm_mixer::~scumm_mixer() { +} + +bool scumm_mixer::init() { + debug(9, "scumm_mixer::init()"); + return true; +} + +_Channel * scumm_mixer::findChannel(int track) { + debug(9, "scumm_mixer::findChannel(%d)", track); + for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) { + if(_channels[i].id == track) + return _channels[i].chan; + } + return 0; +} + +bool scumm_mixer::addChannel(_Channel * c) { + int track = c->getTrackIdentifier(); + int i; + + debug(9, "scumm_mixer::addChannel(%d)", track); + + for(i = 0; i < SoundMixer::NUM_CHANNELS; i++) { + if(_channels[i].id == track) + warning("mixer::addChannel(%d) : channel already exist !", track); + } + if(_nextIndex >= SoundMixer::NUM_CHANNELS) _nextIndex = 0; + + for(i = _nextIndex; i < SoundMixer::NUM_CHANNELS; i++) { + if(_channels[i].chan == 0 || _channels[i].id == -1) { + _channels[i].chan = c; + _channels[i].id = track; + _channels[i].first = true; + _nextIndex = i + 1; + return true; + } + } + + for(i = 0; i < _nextIndex; i++) { + if(_channels[i].chan == 0 || _channels[i].id == -1) { + _channels[i].chan = c; + _channels[i].id = track; + _channels[i].first = true; + _nextIndex = i + 1; + return true; + } + } + + fprintf(stderr, "_nextIndex == %d\n", _nextIndex); + + for(i = 0; i < SoundMixer::NUM_CHANNELS; i++) { + fprintf(stderr, "channel %d : %p(%d, %d) %d %d\n", i, _channels[i].chan, + _channels[i].chan ? _channels[i].chan->getTrackIdentifier() : -1, + _channels[i].chan ? _channels[i].chan->isTerminated() : 1, + _channels[i].first, _channels[i].mixer_index); + } + + error("mixer::add_channel() : no more channel available"); + return false; +} + +bool scumm_mixer::handleFrame() { + debug(9, "scumm_mixer::handleFrame()"); + for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) { + if(_channels[i].id != -1) { + debug(9, "updating channel %d (%p)", _channels[i].id, _channels[i].chan); + if(_channels[i].chan->isTerminated()) { + debug(9, "channel %d has terminated (%p)", _channels[i].id, _channels[i].chan); + delete _channels[i].chan; + _channels[i].id = -1; + _channels[i].chan = 0; + } else { + int rate; + bool stereo, is_short; + + _channels[i].chan->getParameters(rate, stereo, is_short); + int size = _channels[i].chan->availableSoundData(); + debug(9, "channel %d : %d, %s, %d bits, %d", _channels[i].id, rate, stereo ? "stereo" : "mono", is_short ? 16 : 8, size); + int flags = stereo ? SoundMixer::FLAG_STEREO : 0; + + if(is_short) { + // FIXME this is one more data copy... we could get rid of it... + short * data = new short[size * (stereo ? 2 : 1)]; + _channels[i].chan->getSoundData(data, size); + size *= stereo ? 4 : 2; + + // append to _sound + if(_channels[i].first) { + _channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_16BITS); + debug(5, "channel %d bound to mixer_index %d", _channels[i].id, _channels[i].mixer_index); + _channels[i].first = false; + } else { + _mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_16BITS); + } + + delete []data; + } else { + char * data = new char[size*(stereo ? 2 : 1)]; + _channels[i].chan->getSoundData(data, size); + size *= stereo ? 2 : 1; + + // append to _sound + if(_channels[i].first) { + _channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED); + _channels[i].first = false; + } else { + _mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED); + } + + delete []data; + } + } + } + } + return true; +} + +bool scumm_mixer::stop() { + debug(9, "scumm_mixer::stop()"); + for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) { + if(_channels[i].id != -1) { + delete _channels[i].chan; + _channels[i].id = -1; + _channels[i].chan = 0; + } + } + //~ _mixer->stopAll(); + return true; +} + +ScummRenderer::ScummRenderer(Scumm * scumm) : _scumm(scumm), _smixer(0) { +} + +static ScummRenderer * s_renderer; + +static void smush_handler(Scumm * scumm) { + s_renderer->update(); +} + +Mixer * ScummRenderer::getMixer() { + if(_smixer == 0) { + _scumm->_sound->pauseBundleMusic(true); + _smixer = new scumm_mixer(_scumm->_mixer); + if(!_smixer) error("unable to allocate a smush mixer"); + s_renderer = this; + _scumm->_timer->installProcedure(&smush_handler, 75); + } + return _smixer; +} + +ScummRenderer::~ScummRenderer() { + _scumm->_insaneState = 0; + _scumm->exitCutscene(); + if(_smixer) { + _scumm->_timer->releaseProcedure(&smush_handler); + delete _smixer; + _smixer = 0; + } + _scumm->_sound->pauseBundleMusic(false); +} + +bool ScummRenderer::wait(int ms) { + while(_wait) { + _scumm->waitForTimer(1); + } + return true; +} + +bool ScummRenderer::startDecode(const char * fname, int version, int nbframes) { + _scumm->_sound->pauseBundleMusic(true); + _scumm->videoFinished = 0; + _scumm->_insaneState = 1; + return true; +} + +bool ScummRenderer::setPalette(const Palette & pal) { + int i; + byte palette_colors[1024]; + byte *p = palette_colors; + + for (i = 0; i < 256; i++, p += 4) { + p[0] = pal[i].red(); + p[1] = pal[i].green(); + p[2] = pal[i].blue(); + p[3] = 0; + } + + _scumm->_system->set_palette(palette_colors, 0, 256); + _scumm->setDirtyColors(0, 255); + return BaseRenderer::setPalette(pal); // For compatibility with possible subclass... +} + +void ScummRenderer::save(int frame) { + int width = min(getWidth(), _scumm->_realWidth); + int height = min(getHeight(), _scumm->_realHeight); + + _scumm->_system->copy_rect((const byte *)data(), getWidth(), 0, 0, width, height); + _scumm->_system->update_screen(); + _scumm->processKbd(); + _wait = true; +} + +bool ScummRenderer::prematureClose() { + return _scumm->videoFinished; +} + +bool ScummRenderer::update() { + _wait = false; + return true; +} + diff --git a/scumm/smush/scumm_renderer.h b/scumm/smush/scumm_renderer.h new file mode 100644 index 00000000000..097c657c17e --- /dev/null +++ b/scumm/smush/scumm_renderer.h @@ -0,0 +1,66 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 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$ + * + */ + +#ifndef __SCUMM_RENDERER_H_ +#define __SCUMM_RENDERER_H_ + +#include "config.h" + +#ifdef DEBUG +# ifndef NO_DEBUG_SCUMM_RENDERER +# define DEBUG_SCUMM_RENDERER +# endif +#else +# ifdef DEBUG_SCUMM_RENDERER +# error DEBUG_SCUMM_RENDERER defined without DEBUG +# endif +#endif + +#include "brenderer.h" +#include "mixer.h" +#include "rect.h" +#include "blitter.h" + +#ifndef min +#define min(x, y) ((x) > (y) ? (y) : (x)) +#endif + +class scumm_mixer; + +class ScummRenderer : public BaseRenderer { +private: + Scumm * _scumm; + scumm_mixer * _smixer; + volatile bool _wait; +public: + ScummRenderer(Scumm * scumm); + virtual ~ScummRenderer(); + virtual bool wait(int ms); + bool update(); +protected: + virtual bool startDecode(const char * fname, int version, int nbframes); + virtual bool setPalette(const Palette & pal); + virtual void save(int frame = -1); + virtual Mixer * getMixer(); + virtual bool prematureClose(); +}; + +#endif diff --git a/simon/simon.cpp b/simon/simon.cpp index 358cc42e98e..2e24facc48e 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -128,7 +128,7 @@ SimonState::SimonState(GameDetector *detector, OSystem *syst) _game = detector->_gameId; /* Setup mixer */ - if (!_mixer->bind_to_system(syst)) + if (!_mixer->bindToSystem(syst)) warning("Sound initialization failed. " "Features of the game that depend on sound synchronization will most likely break"); set_volume(detector->_sfx_volume); @@ -3296,7 +3296,7 @@ void SimonState::readSfxFile(const char *filename) fseek(in, 0, SEEK_SET); /* stop all sounds */ - _mixer->stop_all(); + _mixer->stopAll(); if (_sfx_heap) free(_sfx_heap); @@ -4038,12 +4038,11 @@ void SimonState::read_vga_from_datfile_1(uint vga_id) FILE *in; char buf[50]; uint32 size; - - // FIXME - weird hack to make the beard show up when wearing it (see bug #590800) - if (vga_id == 328) - sprintf(buf, "0119.VGA"); - else - sprintf(buf, "%.3d%d.VGA", vga_id >> 1, (vga_id & 1) + 1); + // FIXME - weird hack to make the beard show up when wearing it (see bug #590800) + if (vga_id == 328) + sprintf(buf, "0119.VGA"); + else + sprintf(buf, "%.3d%d.VGA", vga_id >> 1, (vga_id & 1) + 1); in = fopen_maybe_lowercase(buf); if (in == NULL) { @@ -4798,7 +4797,7 @@ void SimonState::playVoice(uint voice) byte *buffer = (byte *)malloc(data[1]); fread(buffer, data[1], 1, _voice_file); - _mixer->play_raw(&_voice_sound, buffer, data[1], READ_LE_UINT32(&wave_hdr.samples_per_sec), + _mixer->playRaw(&_voice_sound, buffer, data[1], READ_LE_UINT32(&wave_hdr.samples_per_sec), SoundMixer::FLAG_UNSIGNED); } else { /* VOC audio */ VocHeader voc_hdr; @@ -4821,7 +4820,7 @@ void SimonState::playVoice(uint voice) byte *buffer = (byte *)malloc(size); fread(buffer, size, 1, _voice_file); - _mixer->play_raw(&_voice_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED); + _mixer->playRaw(&_voice_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED); } } @@ -4854,7 +4853,7 @@ void SimonState::playSound(uint sound) byte *buffer = (byte *)malloc(size); fread(buffer, size, 1, _effects_file); - _mixer->play_raw(&_effects_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED); + _mixer->playRaw(&_effects_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED); } else { byte *p; @@ -4880,7 +4879,7 @@ void SimonState::playSound(uint sound) p++; } - _mixer->play_raw(&_playing_sound, p + 8, READ_LE_UINT32(p + 4), 22050, + _mixer->playRaw(&_playing_sound, p + 8, READ_LE_UINT32(p + 4), 22050, SoundMixer::FLAG_UNSIGNED); } } else { @@ -4938,7 +4937,7 @@ void SimonState::dx_unlock_attached() void SimonState::set_volume(byte volume) { - _mixer->set_volume(volume); + _mixer->setVolume(volume); } diff --git a/simon/vga.cpp b/simon/vga.cpp index 39d56d0c85c..bbffb53611e 100644 --- a/simon/vga.cpp +++ b/simon/vga.cpp @@ -1367,7 +1367,7 @@ void SimonState::vc_28() void SimonState::vc_29_stop_all_sounds() { - _mixer->stop_all(); + _mixer->stopAll(); } void SimonState::vc_30_set_base_delay() diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp index c7825673a5b..b1a0cf163dc 100644 --- a/sound/mididrv.cpp +++ b/sound/mididrv.cpp @@ -1075,7 +1075,7 @@ MidiDriver_MIDIEMU::MidiDriver_MIDIEMU() int MidiDriver_MIDIEMU::open(int mode) { _opl = OPLCreate(OPL_TYPE_YM3812, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0)); - g_mixer->setup_premix((void *)this, premix_proc); + g_mixer->setupPremix((void *)this, premix_proc); if (_stream_proc) g_system->create_thread(midiemu_callback_thread, this); return 0; diff --git a/sound/mixer.cpp b/sound/mixer.cpp index 38f25ed6e46..21a606448d1 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -23,19 +23,15 @@ #include "stdafx.h" #include "scumm.h" -SoundMixer::SoundMixer() -{ - _volume_table = (int16 *)calloc(256 * sizeof(int16), 1); +SoundMixer::SoundMixer() { + _volumeTable = (int16 *)calloc(256 * sizeof(int16), 1); } -SoundMixer::~SoundMixer() -{ - free(_volume_table); +SoundMixer::~SoundMixer() { + free(_volumeTable); } -void SoundMixer::uninsert(Channel * chan) -{ - +void SoundMixer::unInsert(Channel * chan) { for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] == chan) { if (_handles[i]) { @@ -49,14 +45,13 @@ void SoundMixer::uninsert(Channel * chan) error("SoundMixer::channel_deleted chan not found"); } -int SoundMixer::append(int index, void *sound, uint32 size, uint rate, byte flags) -{ +int SoundMixer::append(int index, void * sound, uint32 size, uint rate, byte flags) { _syst->lock_mutex(_mutex); - Channel *chan = _channels[index]; + Channel * chan = _channels[index]; if (!chan) { - warning("Trying to stream to an unexistant streamer "); - play_stream(NULL, index, sound, size, rate, flags); + warning("Trying to stream to an unexistant streamer : %d", index); + playStream(NULL, index, sound, size, rate, flags); chan = _channels[index]; } else { chan->append(sound, size); @@ -68,8 +63,15 @@ int SoundMixer::append(int index, void *sound, uint32 size, uint rate, byte flag return 1; } -int SoundMixer::insert_at(PlayingSoundHandle *handle, int index, Channel * chan) -{ +int SoundMixer::insertAt(PlayingSoundHandle * handle, int index, Channel * chan) { + if(index == -1) { + for (int i = 0; i != NUM_CHANNELS; i++) + if (_channels[i] == NULL) { index = i; break; } + if(index == -1) { + warning("SoundMixer::out of mixer slots"); + return -1; + } + } if (_channels[index] != NULL) { error("Trying to put a mixer where it cannot go "); } @@ -80,12 +82,11 @@ int SoundMixer::insert_at(PlayingSoundHandle *handle, int index, Channel * chan) return index; } -int SoundMixer::play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, - byte flags) -{ +int SoundMixer::playRaw(PlayingSoundHandle * handle, void * sound, uint32 size, uint rate, + byte flags) { for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] == NULL) { - return insert_at(handle, i, new Channel_RAW(this, sound, size, rate, flags)); + return insertAt(handle, i, new ChannelRaw(this, sound, size, rate, flags)); } } @@ -93,30 +94,27 @@ int SoundMixer::play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, u return -1; } -int SoundMixer::play_stream(PlayingSoundHandle *handle, int idx, void *sound, uint32 size, - uint rate, byte flags) -{ - return insert_at(handle, idx, new Channel_STREAM(this, sound, size, rate, flags)); +int SoundMixer::playStream(PlayingSoundHandle * handle, int idx, void * sound, uint32 size, + uint rate, byte flags) { + return insertAt(handle, idx, new ChannelStream(this, sound, size, rate, flags)); } #ifdef COMPRESSED_SOUND_FILE -int SoundMixer::play_mp3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags) -{ +int SoundMixer::playMP3(PlayingSoundHandle * handle, void *sound, uint32 size, byte flags) { for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] == NULL) { - return insert_at(handle, i, new Channel_MP3(this, sound, size, flags)); + return insertAt(handle, i, new ChannelMP3(this, sound, size, flags)); } } warning("SoundMixer::out of mixer slots"); return -1; } -int SoundMixer::play_mp3_cdtrack(PlayingSoundHandle *handle, FILE * file, mad_timer_t duration) -{ +int SoundMixer::playMP3CDTrack(PlayingSoundHandle * handle, FILE * file, mad_timer_t duration) { /* Stop the previously playing CD track (if any) */ for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] == NULL) { - return insert_at(handle, i, new Channel_MP3_CDMUSIC(this, file, duration)); + return insertAt(handle, i, new ChannelMP3CDMusic(this, file, duration)); } } @@ -125,16 +123,15 @@ int SoundMixer::play_mp3_cdtrack(PlayingSoundHandle *handle, FILE * file, mad_ti } #endif -void SoundMixer::mix(int16 *buf, uint len) -{ +void SoundMixer::mix(int16 *buf, uint len) { if (_paused) { memset(buf, 0, 2 * len * sizeof(int16)); return; } - if (_premix_proc) { + if (_premixProc) { int i; - _premix_proc(_premix_param, buf, len); + _premixProc(_premixParam, buf, len); for (i = (len - 1); i >= 0; i--) { buf[2 * i] = buf[2 * i + 1] = buf[i]; } @@ -151,16 +148,14 @@ void SoundMixer::mix(int16 *buf, uint len) _syst->unlock_mutex(_mutex); } -void SoundMixer::on_generate_samples(void *s, byte *samples, int len) -{ +void SoundMixer::onGenerateSamples(void * s, byte * samples, int len) { ((SoundMixer *)s)->mix((int16 *)samples, len >> 2); } -bool SoundMixer::bind_to_system(OSystem *syst) -{ +bool SoundMixer::bindToSystem(OSystem * syst) { uint rate = (uint) syst->property(OSystem::PROP_GET_SAMPLE_RATE, 0); - _output_rate = rate; + _outputRate = rate; _syst = syst; _mutex = _syst->create_mutex(); @@ -168,49 +163,42 @@ bool SoundMixer::bind_to_system(OSystem *syst) if (rate == 0) error("OSystem returned invalid sample rate"); - return syst->set_sound_proc(this, on_generate_samples, OSystem::SOUND_16BIT); + return syst->set_sound_proc(this, onGenerateSamples, OSystem::SOUND_16BIT); } -void SoundMixer::stop_all() -{ +void SoundMixer::stopAll() { for (int i = 0; i != NUM_CHANNELS; i++) if (_channels[i]) _channels[i]->destroy(); } -void SoundMixer::stop(PlayingSoundHandle psh) -{ +void SoundMixer::stop(PlayingSoundHandle psh) { if (psh && _channels[psh - 1]) _channels[psh - 1]->destroy(); } -void SoundMixer::stop(int index) -{ +void SoundMixer::stop(int index) { if (_channels[index]) _channels[index]->destroy(); } -void SoundMixer::pause(bool paused) -{ +void SoundMixer::pause(bool paused) { _paused = paused; } -bool SoundMixer::has_active_channel() -{ +bool SoundMixer::hasActiveChannel() { for (int i = 0; i != NUM_CHANNELS; i++) if (_channels[i]) return true; return false; } -void SoundMixer::setup_premix(void *param, PremixProc *proc) -{ - _premix_param = param; - _premix_proc = proc; +void SoundMixer::setupPremix(void * param, PremixProc * proc) { + _premixParam = param; + _premixProc = proc; } -void SoundMixer::set_volume(int volume) -{ +void SoundMixer::setVolume(int volume) { int i; // Check range @@ -221,55 +209,51 @@ void SoundMixer::set_volume(int volume) // The volume table takes 8 bit unsigned data as index and returns 16 bit signed for (i = 0; i < 128; i++) - _volume_table[i] = i * volume; + _volumeTable[i] = i * volume; for (i = -128; i < 0; i++) - _volume_table[i+256] = i * volume; + _volumeTable[i + 256] = i * volume; } -void SoundMixer::set_music_volume(int volume) -{ +void SoundMixer::setMusicVolume(int volume) { // Check range if (volume > 256) volume = 256; else if (volume < 0) volume = 0; - _music_volume = volume; + _musicVolume = volume; } #ifdef COMPRESSED_SOUND_FILE -bool SoundMixer::Channel::sound_finished() -{ +bool SoundMixer::Channel::soundFinished() { warning("sound_finished should never be called on a non-MP3 mixer "); return false; } #endif -void SoundMixer::Channel::append(void *sound, uint32 size) -{ +void SoundMixer::Channel::append(void * sound, uint32 size) { error("append method should never be called on something else than a _STREAM mixer "); } /* RAW mixer */ -SoundMixer::Channel_RAW::Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, - byte flags) -{ +SoundMixer::ChannelRaw::ChannelRaw(SoundMixer * mixer, void * sound, uint32 size, uint rate, + byte flags) { _mixer = mixer; _flags = flags; _ptr = sound; _pos = 0; - _fp_pos = 0; - _fp_speed = (1 << 16) * rate / mixer->_output_rate; - _to_be_destroyed = false; - _realsize = size; + _fpPos = 0; + _fpSpeed = (1 << 16) * rate / mixer->_outputRate; + _toBeDestroyed = false; + _realSize = size; // adjust the magnitude to prevent division error while (size & 0xFFFF0000) size >>= 1, rate = (rate >> 1) + 1; _rate = rate; - _size = size * mixer->_output_rate / rate; + _size = size * mixer->_outputRate / rate; if (_flags & FLAG_16BITS) _size = _size >> 1; if (_flags & FLAG_STEREO) @@ -288,7 +272,7 @@ protected: int a, b, c, d; public: - CubicInterpolator(int a, int b, int c) : x0(2*a-b), x1(a), x2(b), x3(c) + CubicInterpolator(int a, int b, int c) : x0(2 * a - b), x1(a), x2(b), x3(c) { // We use a simple linear interpolation for x0 updateCoefficients(); @@ -299,7 +283,7 @@ public: x0 = x1; x1 = x2; x2 = x3; - x3 = 2*x2-x1; // Simple linear interpolation + x3 = 2 * x2 - x1; // Simple linear interpolation updateCoefficients(); } @@ -313,14 +297,14 @@ public: } /* t must be a 16.16 fixed point number between 0 and 1 */ - inline int interpolate(uint32 fp_pos) + inline int interpolate(uint32 fpPos) { int result = 0; - int t = fp_pos >> 8; - result = (a*t + b) >> 8; + int t = fpPos >> 8; + result = (a * t + b) >> 8; result = (result * t + c) >> 8; result = (result * t + d) >> 8; - result = (result/3 + 1) >> 1; + result = (result / 3 + 1) >> 1; return result; } @@ -328,15 +312,14 @@ public: protected: inline void updateCoefficients() { - a = ((-x0*2)+(x1*5)-(x2*4)+x3); - b = ((x0+x2-(2*x1))*6) << 8; - c = ((-4*x0)+x1+(x2*4)-x3) << 8; - d = (x1*6) << 8; + a = ((-x0 * 2) + (x1 * 5) - (x2 * 4) + x3); + b = ((x0 + x2 - (2 * x1)) * 6) << 8; + c = ((-4 * x0) + x1 + (x2 * 4) - x3) << 8; + d = (x1 * 6) << 8; } }; -static inline int clamped_add_16(int a, int b) -{ +static inline int clamped_add_16(int a, int b) { int val = a + b; if (val > 32767) { @@ -347,15 +330,14 @@ static inline int clamped_add_16(int a, int b) return val; } -static int16 *mix_signed_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ +static int16 * mix_signed_mono_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { uint32 fp_pos = *fp_pos_ptr; byte *s = *s_ptr; uint len = *len_ptr; int inc = 1, result; - CubicInterpolator interp(vol_tab[*s], vol_tab[*(s+1)], vol_tab[*(s+2)]); + CubicInterpolator interp(vol_tab[*s], vol_tab[*(s + 1)], vol_tab[*(s + 2)]); do { do { @@ -373,8 +355,8 @@ static int16 *mix_signed_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint3 fp_pos &= 0x0000FFFF; } while (!inc && len && (s < s_end)); - if (s+2 < s_end) - interp.feedData(vol_tab[*(s+2)]); + if (s + 2 < s_end) + interp.feedData(vol_tab[*(s + 2)]); else interp.feedData(); @@ -386,15 +368,15 @@ static int16 *mix_signed_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint3 return data; } -static int16 *mix_unsigned_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ + +static int16 * mix_unsigned_mono_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { uint32 fp_pos = *fp_pos_ptr; byte *s = *s_ptr; uint len = *len_ptr; int inc = 1, result; - CubicInterpolator interp(vol_tab[*s ^ 0x80], vol_tab[*(s+1) ^ 0x80], vol_tab[*(s+2) ^ 0x80]); + CubicInterpolator interp(vol_tab[*s ^ 0x80], vol_tab[*(s + 1) ^ 0x80], vol_tab[*(s + 2) ^ 0x80]); do { do { @@ -412,8 +394,8 @@ static int16 *mix_unsigned_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uin fp_pos &= 0x0000FFFF; } while (!inc && len && (s < s_end)); - if (s+2 < s_end) - interp.feedData(vol_tab[*(s+2) ^ 0x80]); + if (s + 2 < s_end) + interp.feedData(vol_tab[*(s + 2) ^ 0x80]); else interp.feedData(); @@ -425,23 +407,22 @@ static int16 *mix_unsigned_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uin return data; } -static int16 *mix_signed_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ + +static int16 * mix_signed_stereo_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte *s_end) { warning("Mixing stereo signed 8 bit is not supported yet "); return data; } -static int16 *mix_unsigned_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ +static int16 * mix_unsigned_stereo_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { uint32 fp_pos = *fp_pos_ptr; byte *s = *s_ptr; uint len = *len_ptr; int inc = 1; - CubicInterpolator left(vol_tab[*s ^ 0x80], vol_tab[*(s+2) ^ 0x80], vol_tab[*(s+4) ^ 0x80]); - CubicInterpolator right(vol_tab[*(s+1) ^ 0x80], vol_tab[*(s+3) ^ 0x80], vol_tab[*(s+5) ^ 0x80]); + CubicInterpolator left(vol_tab[*s ^ 0x80], vol_tab[*(s + 2) ^ 0x80], vol_tab[*(s + 4) ^ 0x80]); + CubicInterpolator right(vol_tab[*(s + 1) ^ 0x80], vol_tab[*(s + 3) ^ 0x80], vol_tab[*(s + 5) ^ 0x80]); do { do { @@ -457,9 +438,9 @@ static int16 *mix_unsigned_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, u fp_pos &= 0x0000FFFF; } while (!inc && len && (s < s_end)); - if (s+5 < s_end) { - left.feedData(vol_tab[*(s+4) ^ 0x80]); - right.feedData(vol_tab[*(s+5) ^ 0x80]); + if (s + 5 < s_end) { + left.feedData(vol_tab[*(s + 4) ^ 0x80]); + right.feedData(vol_tab[*(s + 5) ^ 0x80]); } else { left.feedData(); right.feedData(); @@ -473,9 +454,8 @@ static int16 *mix_unsigned_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, u return data; } -static int16 *mix_signed_mono_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ +static int16 * mix_signed_mono_16(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { uint32 fp_pos = *fp_pos_ptr; unsigned char volume = ((int)vol_tab[1]) / 8; byte *s = *s_ptr; @@ -499,16 +479,14 @@ static int16 *mix_signed_mono_16(int16 *data, uint * len_ptr, byte **s_ptr, uint return data; } -static int16 *mix_unsigned_mono_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ +static int16 *mix_unsigned_mono_16(int16 *data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { warning("Mixing mono unsigned 16 bit is not supported yet "); return data; } -static int16 *mix_signed_stereo_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ +static int16 *mix_signed_stereo_16(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { uint32 fp_pos = *fp_pos_ptr; unsigned char volume = ((int)vol_tab[1]) / 8; byte *s = *s_ptr; @@ -531,28 +509,29 @@ static int16 *mix_signed_stereo_16(int16 *data, uint * len_ptr, byte **s_ptr, ui return data; } -static int16 *mix_unsigned_stereo_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, - int fp_speed, const int16 *vol_tab, byte *s_end) -{ +static int16 * mix_unsigned_stereo_16(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr, + int fp_speed, const int16 * vol_tab, byte * s_end) { warning("Mixing stereo unsigned 16 bit is not supported yet "); return data; } -static int16 *(*mixer_helper_table[8]) (int16 *data, uint * len_ptr, byte **s_ptr, - uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, - byte *s_end) = { -mix_signed_mono_8, mix_unsigned_mono_8, mix_signed_stereo_8, mix_unsigned_stereo_8, - mix_signed_mono_16, mix_unsigned_mono_16, mix_signed_stereo_16, mix_unsigned_stereo_16}; +static int16 * (*mixer_helper_table[8]) (int16 * data, uint * len_ptr, byte ** s_ptr, + uint32 * fp_pos_ptr, int fp_speed, const int16 * vol_tab, + byte * s_end) = { + mix_signed_mono_8, mix_unsigned_mono_8, + mix_signed_stereo_8, mix_unsigned_stereo_8, + mix_signed_mono_16, mix_unsigned_mono_16, + mix_signed_stereo_16, mix_unsigned_stereo_16 +}; -void SoundMixer::Channel_RAW::mix(int16 *data, uint len) -{ +void SoundMixer::ChannelRaw::mix(int16 * data, uint len) { byte *s, *s_org = NULL; uint32 fp_pos; byte *end; - if (_to_be_destroyed) { - real_destroy(); + if (_toBeDestroyed) { + realDestroy(); return; } @@ -565,11 +544,11 @@ void SoundMixer::Channel_RAW::mix(int16 *data, uint len) */ if (_flags & FLAG_FILE) { /* determine how many samples to read from the file */ - uint num = len * _fp_speed >> 16; + uint num = len * _fpSpeed >> 16; s_org = (byte *)malloc(num); if (s_org == NULL) - error("Channel_RAW::mix out of memory"); + error("ChannelRaw::mix out of memory"); uint num_read = fread(s_org, 1, num, (FILE *) _ptr); if (num - num_read != 0) @@ -580,141 +559,116 @@ void SoundMixer::Channel_RAW::mix(int16 *data, uint len) end = s_org + num; } else { s = (byte *)_ptr + _pos; - fp_pos = _fp_pos; - end = (byte *)_ptr + _realsize; + fp_pos = _fpPos; + end = (byte *)_ptr + _realSize; } - const uint32 fp_speed = _fp_speed; - const int16 *vol_tab = _mixer->_volume_table; + const uint32 fp_speed = _fpSpeed; + const int16 *vol_tab = _mixer->_volumeTable; mixer_helper_table[_flags & 0x07] (data, &len, &s, &fp_pos, fp_speed, vol_tab, end); _pos = s - (byte *)_ptr; - _fp_pos = fp_pos; + _fpPos = fp_pos; if (_flags & FLAG_FILE) { free(s_org); } if (_size < 1) - real_destroy(); + realDestroy(); } -void SoundMixer::Channel_RAW::real_destroy() -{ +void SoundMixer::ChannelRaw::realDestroy() { if (_flags & FLAG_AUTOFREE) free(_ptr); - _mixer->uninsert(this); + _mixer->unInsert(this); delete this; } -/* STREAM mixer */ -SoundMixer::Channel_STREAM::Channel_STREAM(SoundMixer *mixer, void *sound, uint32 size, uint rate, - byte flags) -{ +SoundMixer::ChannelStream::ChannelStream(SoundMixer * mixer, void * sound, uint32 size, uint rate, + byte flags) { _mixer = mixer; _flags = flags; - _buffer_size = 1024 * size; - _ptr = (byte *)malloc(_buffer_size); + _bufferSize = 1024 * size; + _ptr = (byte *)malloc(_bufferSize); memcpy(_ptr, sound, size); - _end_of_data = _ptr + size; + _endOfData = _ptr + size; if (_flags & FLAG_AUTOFREE) free(sound); _pos = _ptr; - _fp_pos = 0; - _fp_speed = (1 << 16) * rate / mixer->_output_rate; - _to_be_destroyed = false; + _fpPos = 0; + _fpSpeed = (1 << 16) * rate / mixer->_outputRate; + _toBeDestroyed = false; /* adjust the magnitute to prevent division error */ while (size & 0xFFFF0000) size >>= 1, rate = (rate >> 1) + 1; - _rate = rate; } -void SoundMixer::Channel_STREAM::append(void *data, uint32 len) -{ - byte *new_end = _end_of_data + len; +void SoundMixer::ChannelStream::append(void * data, uint32 len) { + byte *new_end = _endOfData + len; byte *cur_pos = _pos; /* This is just to prevent the variable to move during the tests :-) */ - if (new_end > (_ptr + _buffer_size)) { + if (new_end > (_ptr + _bufferSize)) { /* Wrap-around case */ - new_end = _ptr + len - ((_ptr + _buffer_size) - _end_of_data); - if ((_end_of_data < cur_pos) || (new_end >= cur_pos)) { + new_end = _ptr + len - ((_ptr + _bufferSize) - _endOfData); + if ((_endOfData < cur_pos) || (new_end >= cur_pos)) { warning("Mixer full... Trying to not break too much "); return; } - memcpy(_end_of_data, data, (_ptr + _buffer_size) - _end_of_data); - memcpy(_ptr, (byte *)data + ((_ptr + _buffer_size) - _end_of_data), - len - ((_ptr + _buffer_size) - _end_of_data)); + memcpy(_endOfData, data, (_ptr + _bufferSize) - _endOfData); + memcpy(_ptr, (byte *)data + ((_ptr + _bufferSize) - _endOfData), + len - ((_ptr + _bufferSize) - _endOfData)); } else { - if ((_end_of_data < cur_pos) && (new_end >= cur_pos)) { + if ((_endOfData < cur_pos) && (new_end >= cur_pos)) { warning("Mixer full... Trying to not break too much "); return; } - memcpy(_end_of_data, data, len); + memcpy(_endOfData, data, len); } - _end_of_data = new_end; + _endOfData = new_end; } -void SoundMixer::Channel_STREAM::mix(int16 *data, uint len) -{ +void SoundMixer::ChannelStream::mix(int16 * data, uint len) { uint32 fp_pos; - const uint32 fp_speed = _fp_speed; - const int16 *vol_tab = _mixer->_volume_table; - byte *end_of_data = _end_of_data; + const uint32 fp_speed = _fpSpeed; + const int16 * vol_tab = _mixer->_volumeTable; + byte * end_of_data = _endOfData; - if (_to_be_destroyed) { - real_destroy(); + if (_toBeDestroyed) { + realDestroy(); return; } - fp_pos = _fp_pos; + fp_pos = _fpPos; if (_pos < end_of_data) { mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data); } else { -// mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, -// _ptr + _buffer_size); -// if (len != 0) { -// _pos = _ptr; -// mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, -// end_of_data); -// } else - _to_be_destroyed = true; + _toBeDestroyed = true; } - if (len != 0) { - // FIXME: BBrox, what does this mean? :) - // Commented by Ender to remove non-existant - // streamer bug in Dig smush movies. - //warning("Streaming underflow of %d bytes", len); - //real_destroy(); - //return; - } - _fp_pos = fp_pos; + + _fpPos = fp_pos; } -void SoundMixer::Channel_STREAM::real_destroy() -{ +void SoundMixer::ChannelStream::realDestroy() { free(_ptr); - _mixer->uninsert(this); + _mixer->unInsert(this); delete this; } - - -/* MP3 mixer goes here */ #ifdef COMPRESSED_SOUND_FILE -SoundMixer::Channel_MP3::Channel_MP3(SoundMixer *mixer, void *sound, uint size, byte flags) -{ +SoundMixer::ChannelMP3::ChannelMP3(SoundMixer * mixer, void * sound, uint size, byte flags) { _mixer = mixer; _flags = flags; - _pos_in_frame = 0xFFFFFFFF; + _posInFrame = 0xFFFFFFFF; _position = 0; _size = size; _ptr = sound; - _to_be_destroyed = false; + _toBeDestroyed = false; mad_stream_init(&_stream); #ifdef _WIN32_WCE @@ -735,11 +689,10 @@ SoundMixer::Channel_MP3::Channel_MP3(SoundMixer *mixer, void *sound, uint size, When using Lame, it seems that the sound starts to have some volume about 50 ms from the start of the sound => we skip about 2 frames (at 22.05 khz). */ - _silence_cut = 576 * 2; + _silenceCut = 576 * 2; } -static inline int scale_sample(mad_fixed_t sample) -{ +static inline int scale_sample(mad_fixed_t sample) { /* round */ sample += (1L << (MAD_F_FRACBITS - 16)); @@ -753,44 +706,43 @@ static inline int scale_sample(mad_fixed_t sample) return sample >> (MAD_F_FRACBITS + 2 - 16); } -void SoundMixer::Channel_MP3::mix(int16 *data, uint len) -{ - mad_fixed_t const *ch; - const int16 *vol_tab = _mixer->_volume_table; +void SoundMixer::ChannelMP3::mix(int16 * data, uint len) { + mad_fixed_t const * ch; + const int16 * vol_tab = _mixer->_volumeTable; unsigned char volume = ((int)vol_tab[1]) / 8; - if (_to_be_destroyed) { - real_destroy(); + if (_toBeDestroyed) { + realDestroy(); return; } while (1) { - ch = _synth.pcm.samples[0] + _pos_in_frame; + ch = _synth.pcm.samples[0] + _posInFrame; /* Skip _silence_cut a the start */ - if ((_pos_in_frame < _synth.pcm.length) && (_silence_cut > 0)) { - uint32 diff = _synth.pcm.length - _pos_in_frame; + if ((_posInFrame < _synth.pcm.length) && (_silenceCut > 0)) { + uint32 diff = _synth.pcm.length - _posInFrame; - if (diff > _silence_cut) - diff = _silence_cut; - _silence_cut -= diff; + if (diff > _silenceCut) + diff = _silenceCut; + _silenceCut -= diff; ch += diff; - _pos_in_frame += diff; + _posInFrame += diff; } - while ((_pos_in_frame < _synth.pcm.length) && (len > 0)) { + while ((_posInFrame < _synth.pcm.length) && (len > 0)) { int16 sample = (int16)((scale_sample(*ch) * volume) / 32); *data++ += sample; *data++ += sample; len--; ch++; - _pos_in_frame++; + _posInFrame++; } if (len == 0) return; if (_position >= _size) { - real_destroy(); + realDestroy(); return; } @@ -800,23 +752,22 @@ void SoundMixer::Channel_MP3::mix(int16 *data, uint len) if (mad_frame_decode(&_frame, &_stream) == -1) { /* End of audio... */ if (_stream.error == MAD_ERROR_BUFLEN) { - real_destroy(); + realDestroy(); return; } else if (!MAD_RECOVERABLE(_stream.error)) { error("MAD frame decode error !"); } } mad_synth_frame(&_synth, &_frame); - _pos_in_frame = 0; + _posInFrame = 0; _position = (unsigned char *)_stream.next_frame - (unsigned char *)_ptr; } } -void SoundMixer::Channel_MP3::real_destroy() -{ +void SoundMixer::ChannelMP3::realDestroy() { if (_flags & FLAG_AUTOFREE) free(_ptr); - _mixer->uninsert(this); + _mixer->unInsert(this); mad_synth_finish(&_synth); mad_frame_finish(&_frame); mad_stream_finish(&_stream); @@ -824,19 +775,17 @@ void SoundMixer::Channel_MP3::real_destroy() delete this; } -/* MP3 CD music */ #define MP3CD_BUFFERING_SIZE 131072 -SoundMixer::Channel_MP3_CDMUSIC::Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE * file, - mad_timer_t duration) -{ +SoundMixer::ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer * mixer, FILE * file, + mad_timer_t duration){ _mixer = mixer; _file = file; _duration = duration; _initialized = false; - _buffer_size = MP3CD_BUFFERING_SIZE; + _bufferSize = MP3CD_BUFFERING_SIZE; _ptr = malloc(MP3CD_BUFFERING_SIZE); - _to_be_destroyed = false; + _toBeDestroyed = false; mad_stream_init(&_stream); #ifdef _WIN32_WCE @@ -847,24 +796,23 @@ SoundMixer::Channel_MP3_CDMUSIC::Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE * f mad_synth_init(&_synth); } -void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len) -{ +void SoundMixer::ChannelMP3CDMusic::mix(int16 * data, uint len) { mad_fixed_t const *ch; mad_timer_t frame_duration; - unsigned char volume = _mixer->_music_volume / 8; + unsigned char volume = _mixer->_musicVolume / 8; - if (_to_be_destroyed) { - real_destroy(); + if (_toBeDestroyed) { + realDestroy(); return; } if (!_initialized) { int skip_loop; // just skipped - memset(_ptr, 0, _buffer_size); - _size = fread(_ptr, 1, _buffer_size, _file); + memset(_ptr, 0, _bufferSize); + _size = fread(_ptr, 1, _bufferSize, _file); if (!_size) { - real_destroy(); + realDestroy(); return; } // Resync @@ -880,7 +828,7 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len) } else { if (!MAD_RECOVERABLE(_stream.error)) { debug(1, "Unrecoverable error while skipping !"); - real_destroy(); + realDestroy(); return; } } @@ -890,24 +838,24 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len) mad_synth_mute(&_synth); // Resume decoding if (mad_frame_decode(&_frame, &_stream) == 0) { - _pos_in_frame = 0; + _posInFrame = 0; _initialized = true; } else { debug(1, "Cannot resume decoding"); - real_destroy(); + realDestroy(); return; } } while (1) { // Get samples, play samples ... - ch = _synth.pcm.samples[0] + _pos_in_frame; - while ((_pos_in_frame < _synth.pcm.length) && (len > 0)) { + ch = _synth.pcm.samples[0] + _posInFrame; + while ((_posInFrame < _synth.pcm.length) && (len > 0)) { int16 sample = (int16)((scale_sample(*ch++) * volume) / 32); *data++ += sample; *data++ += sample; len--; - _pos_in_frame++; + _posInFrame++; } if (len == 0) { return; @@ -923,13 +871,13 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len) int not_decoded; if (!_stream.next_frame) { - memset(_ptr, 0, _buffer_size + MAD_BUFFER_GUARD); - _size = fread(_ptr, 1, _buffer_size, _file); + memset(_ptr, 0, _bufferSize + MAD_BUFFER_GUARD); + _size = fread(_ptr, 1, _bufferSize, _file); not_decoded = 0; } else { not_decoded = _stream.bufend - _stream.next_frame; memcpy(_ptr, _stream.next_frame, not_decoded); - _size = fread((unsigned char *)_ptr + not_decoded, 1, _buffer_size - not_decoded, _file); + _size = fread((unsigned char *)_ptr + not_decoded, 1, _bufferSize - not_decoded, _file); } _stream.error = (enum mad_error)0; // Restream @@ -942,19 +890,17 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len) } } mad_synth_frame(&_synth, &_frame); - _pos_in_frame = 0; + _posInFrame = 0; } } -bool SoundMixer::Channel_MP3_CDMUSIC::sound_finished() -{ +bool SoundMixer::ChannelMP3CDMusic::soundFinished() { return mad_timer_compare(_duration, mad_timer_zero) <= 0; } -void SoundMixer::Channel_MP3_CDMUSIC::real_destroy() -{ +void SoundMixer::ChannelMP3CDMusic::realDestroy() { free(_ptr); - _mixer->uninsert(this); + _mixer->unInsert(this); mad_synth_finish(&_synth); mad_frame_finish(&_frame); mad_stream_finish(&_stream); @@ -962,5 +908,4 @@ void SoundMixer::Channel_MP3_CDMUSIC::real_destroy() delete this; } - #endif diff --git a/sound/mixer.h b/sound/mixer.h index 9ce371acd77..19c0414fcda 100644 --- a/sound/mixer.h +++ b/sound/mixer.h @@ -30,110 +30,112 @@ #endif typedef uint32 PlayingSoundHandle; + class SoundMixer { private: class Channel { public: - bool _to_be_destroyed; + bool _toBeDestroyed; virtual void mix(int16 *data, uint len) = 0; void destroy() { - _to_be_destroyed = true; - } virtual void real_destroy() = 0; + _toBeDestroyed = true; + } + virtual void realDestroy() = 0; virtual void append(void *sound, uint32 size); #ifdef COMPRESSED_SOUND_FILE - virtual bool sound_finished(); + virtual bool soundFinished(); #endif }; - class Channel_RAW:public Channel { - SoundMixer *_mixer; - void *_ptr; + class ChannelRaw : public Channel { + SoundMixer * _mixer; + void * _ptr; uint32 _pos; uint32 _size; - uint32 _fp_speed; - uint32 _fp_pos; - uint32 _realsize, _rate; + uint32 _fpSpeed; + uint32 _fpPos; + uint32 _realSize, _rate; byte _flags; - public: - void mix(int16 *data, uint len); - Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags); - void real_destroy(); + ChannelRaw(SoundMixer * mixer, void * sound, uint32 size, uint rate, byte flags); + void mix(int16 * data, uint len); + void realDestroy(); }; - class Channel_STREAM:public Channel { - SoundMixer *_mixer; - byte *_ptr; - byte *_end_of_data; - byte *_pos; - uint32 _fp_speed; - uint32 _fp_pos; - uint32 _buffer_size; + class ChannelStream : public Channel { + SoundMixer * _mixer; + byte * _ptr; + byte * _endOfData; + byte * _pos; + uint32 _fpSpeed; + uint32 _fpPos; + uint32 _bufferSize; uint32 _rate; byte _flags; public: - void append(void *sound, uint32 size); - void mix(int16 *data, uint len); - Channel_STREAM(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags); - void real_destroy(); + ChannelStream(SoundMixer * mixer, void * sound, uint32 size, uint rate, byte flags); + void append(void * sound, uint32 size); + void mix(int16 * data, uint len); + void realDestroy(); }; #ifdef COMPRESSED_SOUND_FILE - class Channel_MP3:public Channel { - SoundMixer *_mixer; + class ChannelMP3 : public Channel { + SoundMixer * _mixer; void *_ptr; struct mad_stream _stream; struct mad_frame _frame; struct mad_synth _synth; - uint32 _silence_cut; - uint32 _pos_in_frame; + uint32 _silenceCut; + uint32 _posInFrame; uint32 _position; uint32 _size; byte _flags; public: - void mix(int16 *data, uint len); - Channel_MP3(SoundMixer *mixer, void *sound, uint size, byte flags); - void real_destroy(); + ChannelMP3(SoundMixer * mixer, void *sound, uint size, byte flags); + void mix(int16 * data, uint len); + void realDestroy(); }; - class Channel_MP3_CDMUSIC:public Channel { - SoundMixer *_mixer; - void *_ptr; + class ChannelMP3CDMusic:public Channel { + SoundMixer * _mixer; + void * _ptr; struct mad_stream _stream; struct mad_frame _frame; struct mad_synth _synth; - uint32 _pos_in_frame; + uint32 _posInFrame; uint32 _size; - uint32 _buffer_size; + uint32 _bufferSize; mad_timer_t _duration; - FILE *_file; + FILE * _file; bool _initialized; + public: - void mix(int16 *data, uint len); - Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE * file, mad_timer_t duration); - void real_destroy(); - bool sound_finished(); + ChannelMP3CDMusic(SoundMixer * mixer, FILE * file, mad_timer_t duration); + void mix(int16 * data, uint len); + void realDestroy(); + bool soundFinished(); }; #endif - static void on_generate_samples(void *s, byte *samples, int len); + static void onGenerateSamples(void * s, byte * samples, int len); public: - typedef void PremixProc (void *param, int16 *data, uint len); + typedef void PremixProc (void * param, int16 * data, uint len); - OSystem *_syst; - void *_mutex; + OSystem * _syst; + void * _mutex; - uint _output_rate; + uint _outputRate; - int16 *_volume_table; - int _music_volume; + int16 * _volumeTable; + int _musicVolume; bool _paused; @@ -141,18 +143,18 @@ public: NUM_CHANNELS = 16, }; - void *_premix_param; - PremixProc *_premix_proc; + void * _premixParam; + PremixProc * _premixProc; - Channel *_channels[NUM_CHANNELS]; - PlayingSoundHandle *_handles[NUM_CHANNELS]; + Channel * _channels[NUM_CHANNELS]; + PlayingSoundHandle * _handles[NUM_CHANNELS]; SoundMixer(); ~SoundMixer(); - int insert_at(PlayingSoundHandle *handle, int index, Channel * chan); - void append(void *data, uint32 len); - void uninsert(Channel * chan); + int insertAt(PlayingSoundHandle * handle, int index, Channel * chan); + void append(void * data, uint32 len); + void unInsert(Channel * chan); /* start playing a raw sound */ enum { @@ -163,41 +165,41 @@ public: FLAG_AUTOFREE = 8, /* sound buffer is freed automagically at the end of playing */ FLAG_FILE = 16, /* sound is a FILE * that's read from */ }; - int play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags); - int play_stream(PlayingSoundHandle *handle, int index, void *sound, uint32 size, uint rate, + int playRaw(PlayingSoundHandle * handle, void * sound, uint32 size, uint rate, byte flags); + int playStream(PlayingSoundHandle * handle, int index, void * sound, uint32 size, uint rate, byte flags); #ifdef COMPRESSED_SOUND_FILE - int play_mp3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags); - int play_mp3_cdtrack(PlayingSoundHandle *handle, FILE * file, mad_timer_t duration); + int playMP3(PlayingSoundHandle * handle, void * sound, uint32 size, byte flags); + int playMP3CDTrack(PlayingSoundHandle * handle, FILE * file, mad_timer_t duration); #endif /* Premix procedure, useful when using fmopl adlib */ - void setup_premix(void *param, PremixProc *proc); + void setupPremix(void * param, PremixProc * proc); /* mix */ - void mix(int16 *buf, uint len); + void mix(int16 * buf, uint len); /* stop all currently playing sounds */ - void stop_all(); + void stopAll(); /* stop playing a specific sound */ void stop(PlayingSoundHandle psh); void stop(int index); /* append to existing sound */ - int append(int index, void *sound, uint32 size, uint rate, byte flags); + int append(int index, void * sound, uint32 size, uint rate, byte flags); /* is any channel active? */ - bool has_active_channel(); + bool hasActiveChannel(); /* bind to the OSystem object => mixer will be * invoked automatically when samples need * to be generated */ - bool bind_to_system(OSystem *syst); + bool bindToSystem(OSystem *syst); /* set the volume, 0-256 */ - void set_volume(int volume); - void set_music_volume(int volume); + void setVolume(int volume); + void setMusicVolume(int volume); /* pause - unpause */ void pause(bool paused); diff --git a/sound/sound.cpp b/sound/sound.cpp index a096774842a..8015ef9ba63 100644 --- a/sound/sound.cpp +++ b/sound/sound.cpp @@ -137,19 +137,19 @@ void Sound::processSoundQues() { byte * buffer = (byte*)malloc (size); memcpy(buffer, ptr, size); if (chan == 1) { - _scumm->_mixer->play_raw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED); + _scumm->_mixer->playRaw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED); } else if (chan == 2) { - _scumm->_mixer->play_raw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_STEREO); + _scumm->_mixer->playRaw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_STEREO); } } else if (bits == 12) { byte * buffer = NULL; uint32 final_size = decode12BitsSample(ptr, &buffer, size); if (chan == 1) { - _scumm->_mixer->play_raw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS); + _scumm->_mixer->playRaw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS); } else if (chan == 2) { - _scumm->_mixer->play_raw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO); + _scumm->_mixer->playRaw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO); } } } @@ -249,7 +249,7 @@ void Sound::playSound(int sound) { // Allocate a sound buffer, copy the data into it, and play char *sound = (char*)malloc(size); memcpy(sound, ptr, size); - _scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + _scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); return; } // Support for Putt-Putt sounds - very hackish, too 8-) @@ -265,15 +265,15 @@ void Sound::playSound(int sound) { // Allocate a sound buffer, copy the data into it, and play char *sound = (char*)malloc(size); - memcpy(sound, ptr+8, size); - _scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + memcpy(sound, ptr + 8, size); + _scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); return; } else if (ptr != NULL && READ_UINT32_UNALIGNED(ptr) == MKID('Crea')) { int size, rate; char * sound = read_creative_voc_file(ptr, size, rate); if(sound != NULL) { - _scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + _scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); } return; } @@ -310,7 +310,7 @@ void Sound::playSound(int sound) { // Allocate a sound buffer, copy the data into it, and play char *sound = (char*)malloc(size); memcpy(sound, ptr + 33, size); - _scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + _scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); return; } @@ -386,7 +386,7 @@ void Sound::playSound(int sound) { // FIXME: Something in the header signifies looping. Need to track it down and add a // mixer flag or something. - _scumm->_mixer->play_raw(NULL, sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + _scumm->_mixer->playRaw(NULL, sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); return; } @@ -676,8 +676,8 @@ void Sound::setupSound() { _scumm->_imuse->set_master_volume(_sound_volume_master); _scumm->_imuse->set_music_volume(_sound_volume_music); - _scumm->_mixer->set_volume(_sound_volume_sfx); - _scumm->_mixer->set_music_volume(_sound_volume_music); + _scumm->_mixer->setVolume(_sound_volume_sfx); + _scumm->_mixer->setMusicVolume(_sound_volume_music); } _sfxFile = openSfxFile(); } @@ -833,12 +833,12 @@ void * Sound::openSfxFile() { } void Sound::stopSfxSound() { - _scumm->_mixer->stop_all(); + _scumm->_mixer->stopAll(); } bool Sound::isSfxFinished() { - return !_scumm->_mixer->has_active_channel(); + return !_scumm->_mixer->hasActiveChannel(); } uint32 Sound::decode12BitsSample(byte * src, byte ** dst, uint32 size) { @@ -985,7 +985,7 @@ void Sound::bundleMusicHandler(Scumm * scumm) { byte * buffer = NULL; uint32 final_size = decode12BitsSample(ptr, &buffer, size); - _scumm->_mixer->play_raw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO); + _scumm->_mixer->playRaw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO); } void Sound::playBundleSound(char *sound) { @@ -1042,7 +1042,7 @@ void Sound::playBundleSound(char *sound) { byte * final = (byte *)malloc(size); memcpy(final, ptr, size); - _scumm->_mixer->play_raw(NULL, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); + _scumm->_mixer->playRaw(NULL, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); } int Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned) { @@ -1051,14 +1051,14 @@ int Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned) { byte flags = SoundMixer::FLAG_AUTOFREE; if (isUnsigned) flags |= SoundMixer::FLAG_UNSIGNED; - return _scumm->_mixer->play_raw(NULL, sound, size, rate, flags); + return _scumm->_mixer->playRaw(NULL, sound, size, rate, flags); } int Sound::playSfxSound_MP3(void *sound, uint32 size) { #ifdef COMPRESSED_SOUND_FILE if (_soundsPaused) return -1; - return _scumm->_mixer->play_mp3(NULL, sound, size, SoundMixer::FLAG_AUTOFREE); + return _scumm->_mixer->playMP3(NULL, sound, size, SoundMixer::FLAG_AUTOFREE); #endif return -1; } @@ -1200,7 +1200,7 @@ int Sound::playMP3CDTrack(int track, int num_loops, int start, int delay) { if (_mp3_cd_playing == true) _scumm->_mixer->stop(_mp3_index); - _mp3_index = _scumm->_mixer->play_mp3_cdtrack(NULL, _mp3_tracks[index], duration); + _mp3_index = _scumm->_mixer->playMP3CDTrack(NULL, _mp3_tracks[index], duration); _mp3_cd_playing = true; return 0; } @@ -1229,7 +1229,7 @@ int Sound::updateMP3CD() { return -1; } - if (_scumm->_mixer->_channels[_mp3_index]->sound_finished()) + if (_scumm->_mixer->_channels[_mp3_index]->soundFinished()) stopMP3CD(); return 0; }