diff options
Diffstat (limited to 'engines/draci/sound.h')
-rw-r--r-- | engines/draci/sound.h | 130 |
1 files changed, 110 insertions, 20 deletions
diff --git a/engines/draci/sound.h b/engines/draci/sound.h index 28379b5429..6e9aae1b6e 100644 --- a/engines/draci/sound.h +++ b/engines/draci/sound.h @@ -28,50 +28,101 @@ #include "common/str.h" #include "common/file.h" +#include "common/list.h" #include "sound/mixer.h" +namespace Common { +class Archive; +class SeekableReadStream; +} + namespace Draci { +enum SoundFormat { RAW, RAW80, MP3, OGG, FLAC }; // RAW80 means skip the first 80 bytes + /** * Represents individual files inside the archive. */ struct SoundSample { - uint _offset; + uint _offset; // For internal use of LegacySoundArchive uint _length; - uint _frequency; - byte* _data; + uint _frequency; // Only when _format == RAW or RAW80 + SoundFormat _format; + + byte *_data; // At most one of these two pointer can be non-NULL + Common::SeekableReadStream* _stream; + + SoundSample() : _offset(0), _length(0), _frequency(0), _format(RAW), _data(NULL), _stream(NULL) { } + // The standard copy constructor is good enough, since we only store numbers and pointers. + // Don't call close() automaticall in the destructor, otherwise copying causes SIGSEGV. void close() { delete[] _data; + delete _stream; _data = NULL; + _stream = NULL; } }; +/** + * An abstract wrapper around archives of sound samples or dubbing. + */ class SoundArchive { public: - SoundArchive(const Common::String &path, uint defaultFreq) : - _path(), _samples(NULL), _sampleCount(0), _defaultFreq(defaultFreq), _opened(false), _f(NULL) { - openArchive(path); - } + SoundArchive() { } + virtual ~SoundArchive() { } - ~SoundArchive() { closeArchive(); } - - void closeArchive(); - void openArchive(const Common::String &path); - uint size() const { return _sampleCount; } + /** + * Returns the number of sound samples in the archive. Zero means that + * a fake empty archive has been opened and the caller may consider + * opening a different one, for example with compressed music. + */ + virtual uint size() const = 0; /** * Checks whether there is an archive opened. Should be called before reading - * from the archive to check whether openArchive() succeeded. + * from the archive to check whether opening of the archive has succeeded. + */ + virtual bool isOpen() const = 0; + + /** + * Removes cached samples from memory. */ - bool isOpen() const { return _opened; } + virtual void clearCache() = 0; + + /** + * Caches a given sample into memory and returns a pointer into it. We + * own the returned pointer, but the user may call .close() on it, + * which deallocates the memory of the actual sample data. If freq is + * nonzero, then the sample is played at a different frequency (only + * works for uncompressed samples). + */ + virtual SoundSample *getSample(int i, uint freq) = 0; +}; - void clearCache(); +/** + * Reads CD.SAM (with dubbing) and CD2.SAM (with sound samples) from the + * original game. Caches all read samples in a thread-safe manner. + */ +class LegacySoundArchive : public SoundArchive { +public: + LegacySoundArchive(const char *path, uint defaultFreq) : + _path(NULL), _samples(NULL), _sampleCount(0), _defaultFreq(defaultFreq), _opened(false), _f(NULL) { + openArchive(path); + } + virtual ~LegacySoundArchive() { closeArchive(); } - SoundSample *getSample(int i, uint freq); + void openArchive(const char *path); + void closeArchive(); + + virtual uint size() const { return _sampleCount; } + virtual bool isOpen() const { return _opened; } + + virtual void clearCache(); + virtual SoundSample *getSample(int i, uint freq); private: - Common::String _path; ///< Path to file + const char *_path; ///< Path to file SoundSample *_samples; ///< Internal array of files uint _sampleCount; ///< Number of files in archive uint _defaultFreq; ///< The default sampling frequency of the archived samples @@ -79,6 +130,44 @@ private: Common::File *_f; ///< Opened file }; +/** + * Reads ZIP archives with uncompressed files containing lossy-compressed + * samples in arbitrary format. Doesn't do any real caching and is + * thread-safe. + */ +class ZipSoundArchive : public SoundArchive { +public: + ZipSoundArchive() : _archive(NULL), _path(NULL), _extension(NULL), _format(RAW), _sampleCount(0), _defaultFreq(0), _cache() { } + virtual ~ZipSoundArchive() { closeArchive(); } + + void openArchive(const char *path, const char *extension, SoundFormat format, int raw_frequency = 0); + void closeArchive(); + + virtual uint size() const { return _sampleCount; } + virtual bool isOpen() const { return _archive != NULL; } + + virtual void clearCache(); + virtual SoundSample *getSample(int i, uint freq); + +private: + Common::Archive *_archive; + const char *_path; + const char *_extension; + SoundFormat _format; + uint _sampleCount; + uint _defaultFreq; + + // Since we typically play at most 1 dubbing at a time, we could get + // away with having just 1 record allocated and reusing it each time. + // However, that would be thread-unsafe if two samples were played. + // Although the player does not do that, it is nicer to allow for it in + // principle. For each dubbed sentence, we allocate a new record in + // the following link-list, which is cleared during each location + // change. The dubbed samples themselves are manually deallocated + // after they end. + Common::List<SoundSample> _cache; +}; + #define SOUND_HANDLES 10 enum sndHandleType { @@ -100,13 +189,13 @@ public: Sound(Audio::Mixer *mixer); ~Sound() {} - void playSound(const SoundSample *buffer, int volume, bool loop); + uint playSound(const SoundSample *buffer, int volume, bool loop); void pauseSound(); void resumeSound(); void stopSound(); bool isMutedSound() const { return _muteSound; } - void playVoice(const SoundSample *buffer); + uint playVoice(const SoundSample *buffer); void pauseVoice(); void resumeVoice(); void stopVoice(); @@ -120,7 +209,8 @@ public: int talkSpeed() const { return _talkSpeed; } private: - void playSoundBuffer(Audio::SoundHandle *handle, const SoundSample &buffer, int volume, + // Returns the length of the sound sample in miliseconds. + uint playSoundBuffer(Audio::SoundHandle *handle, const SoundSample &buffer, int volume, sndHandleType handleType, bool loop); SndHandle *getHandle(); |